////////////////////////////////////////////////////////////////////////// // // pgAdmin III - PostgreSQL Tools // // Copyright (C) 2002 - 2016, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // frmImport.cpp - Import database dialogue // ////////////////////////////////////////////////////////////////////////// // wxWindows headers #include #include #include // App headers #include "pgAdmin3.h" #include "db/pgConn.h" #include "frm/frmMain.h" #include "frm/frmImport.h" #include "utils/sysLogger.h" #include "schema/pgSchema.h" #include "schema/pgTable.h" #include "schema/pgColumn.h" #include "schema/pgPartition.h" // Icons #include "images/reload.pngc" #define nbNotebook CTRL_NOTEBOOK("nbNotebook") #define pickerImportfile CTRL_FILEPICKER("pickerImportfile") #define cbFormat CTRL_COMBOBOX("cbFormat") #define cbEncoding CTRL_COMBOBOX("cbEncoding") #define chkOids CTRL_CHECKBOX("chkOids") #define chkHeader CTRL_CHECKBOX("chkHeader") #define cbDelimiter CTRL_COMBOBOX("cbDelimiter") #define cbQuote CTRL_COMBOBOX("cbQuote") #define cbEscape CTRL_COMBOBOX("cbEscape") #define txtNull CTRL_TEXT("txtNull") #define gauge CTRL_GAUGE("gauge") #define lstColumnsToImport CTRL_CHECKLISTBOX("lstColumnsToImport") #define lstIgnoreForColumns CTRL_CHECKLISTBOX("lstIgnoreForColumns") BEGIN_EVENT_TABLE(frmImport, pgDialog) EVT_COMBOBOX(XRCID("cbFormat"), frmImport::OnChangeFormat) EVT_BUTTON(wxID_OK, frmImport::OnOK) EVT_BUTTON (wxID_HELP, frmImport::OnHelp) END_EVENT_TABLE() frmImport::frmImport(frmMain *form, pgObject *_object, pgConn *_conn) { // Initialize variables connection = _conn; object = _object; done = false; // Set-up window SetFont(settings->GetSystemFont()); LoadResource(form, wxT("frmImport")); RestorePosition(); SetTitle(wxT("Import data from file into ") + object->GetName()); SetIcon(*reload_png_ico); // Fill the encoding combobox long encNo = 0; wxString encStr; cbEncoding->Append(wxT("")); do { encStr = object->GetConnection()->ExecuteScalar( wxT("SELECT pg_encoding_to_char(") + NumToStr(encNo) + wxT(")")); if (pgConn::IsValidServerEncoding(encNo) && !encStr.IsEmpty()) cbEncoding->Append(encStr); encNo++; } while (!encStr.IsEmpty()); cbEncoding->SetSelection(0); // Fill the columns checklistboxes wxCookieType cookie; pgObject *data = 0; wxTreeItemId columnsItem; wxTreeItemId item = form->GetBrowser()->GetFirstChild(object->GetId(), cookie); while (item) { data = form->GetBrowser()->GetObject(item); pgaFactory *factory = data->GetFactory(); if (factory == columnFactory.GetCollectionFactory()) columnsItem = item; if (data->GetMetaType() == PGM_COLUMN && data->IsCollection()) columnsItem = item; if (columnsItem) break; item = form->GetBrowser()->GetNextChild(object->GetId(), cookie); } if (columnsItem) { pgCollection *coll = (pgCollection *)data; coll->ShowTreeDetail(form->GetBrowser()); item = form->GetBrowser()->GetFirstChild(columnsItem, cookie); while (item) { data = form->GetBrowser()->GetObject(item); if (data->IsCreatedBy(columnFactory)) { pgColumn *column = (pgColumn *)data; column->ShowTreeDetail(form->GetBrowser()); if (column->GetColNumber() > 0) { lstColumnsToImport->Append(column->GetName()); lstIgnoreForColumns->Append(column->GetName()); } } item = form->GetBrowser()->GetNextChild(columnsItem, cookie); } for (unsigned int x = 0; x < lstColumnsToImport->GetCount(); x++) lstColumnsToImport->Check(x, true); } // Fix some widgets wxCommandEvent ev; OnChangeFormat(ev); } frmImport::~frmImport() { SavePosition(); } void frmImport::OnHelp(wxCommandEvent &ev) { DisplayHelp(wxT("sql-copy"), HELP_POSTGRESQL); } void frmImport::OnChangeFormat(wxCommandEvent &ev) { bool enabled = cbFormat->GetValue() == wxT("csv"); chkHeader->Enable(enabled); cbQuote->Enable(enabled); cbEscape->Enable(enabled); lstIgnoreForColumns->Enable(enabled); } void frmImport::OnOK(wxCommandEvent &ev) { wxString query = wxEmptyString; wxString columnsToImport = wxEmptyString; wxString columnsToIgnoreForNulls = wxEmptyString; bool allColumnsToImport = true; bool someColumnsToIgnoreForNulls = false; wxFileName fn; wxFile *file; bool copydone = false; bool goterror = false; int nCount = 8192; if (!done) { // Check checklistboxes for (unsigned int x = 0; x < lstColumnsToImport->GetCount(); x++) { if (lstColumnsToImport->IsChecked(x)) { if (!columnsToImport.IsEmpty()) { columnsToImport.Append(wxT(",")); } columnsToImport.Append(qtIdent(lstColumnsToImport->GetString(x))); } else { allColumnsToImport = false; } } for (unsigned int x = 0; x < lstIgnoreForColumns->GetCount(); x++) { if (lstIgnoreForColumns->IsChecked(x)) { if (!columnsToIgnoreForNulls.IsEmpty()) { columnsToIgnoreForNulls.Append(wxT(",")); } columnsToIgnoreForNulls.Append(qtIdent(lstIgnoreForColumns->GetString(x))); someColumnsToIgnoreForNulls = true; } } // Check at least one column is selected else raise a warning if (!allColumnsToImport && columnsToImport.Length() <= 0) { wxMessageBox(_("Please select at least one column to import."), _("Import"), wxICON_WARNING | wxOK, this); return; } // Build COPY query query = wxT("COPY ") + object->GetSchema()->GetQuotedIdentifier() + wxT(".") + object->GetQuotedIdentifier(); if (!allColumnsToImport) { query += wxT("(") + columnsToImport + wxT(")"); } query += wxT(" FROM STDIN "); if (connection->BackendMinimumVersion(9, 0)) { query += wxT("("); query += wxT("FORMAT '") + cbFormat->GetValue() + wxT("'"); if (chkOids->GetValue()) query += wxT(", OIDS"); if (cbDelimiter->GetValue() == wxT("[tab]")) query += wxT(", DELIMITER E'\\t'"); else if (!cbDelimiter->GetValue().IsEmpty()) query += wxT(", DELIMITER ") + connection->qtDbString(cbDelimiter->GetValue()); if (!txtNull->GetValue().IsEmpty()) query += wxT(", NULL ") + connection->qtDbString(txtNull->GetValue()); if (cbFormat->GetValue() == wxT("csv")) { if (chkHeader->GetValue()) query += wxT(", HEADER"); if (!cbQuote->GetValue().IsEmpty()) query += wxT(", QUOTE ") + connection->qtDbString(cbQuote->GetValue()); if (!cbEscape->GetValue().IsEmpty()) query += wxT(", ESCAPE ") + connection->qtDbString(cbEscape->GetValue()); } if (connection->BackendMinimumVersion(9, 1) && !cbEncoding->GetValue().IsEmpty()) query += wxT(", ENCODING ") + connection->qtDbString(cbEncoding->GetValue()); if (cbFormat->GetValue() == wxT("csv")) { if (someColumnsToIgnoreForNulls) query += wxT(", FORCE_NOT_NULL (") + columnsToIgnoreForNulls + wxT(")"); } query += wxT(")"); } else { query += wxT("WITH "); if (cbFormat->GetValue() == wxT("binary")) query += wxT("BINARY "); if (chkOids->GetValue()) query += wxT("OIDS "); if (!cbDelimiter->GetValue().IsEmpty()) query += wxT("DELIMITER ") + connection->qtDbString(cbDelimiter->GetValue()); if (!txtNull->GetValue().IsEmpty()) query += wxT("NULL ") + connection->qtDbString(txtNull->GetValue()); if (cbFormat->GetValue() == wxT("csv")) { query += wxT("CSV "); if (connection->BackendMinimumVersion(8, 0) && chkHeader->GetValue()) query += wxT("HEADER "); if (connection->BackendMinimumVersion(8, 0) && !cbQuote->GetValue().IsEmpty()) query += wxT("QUOTE ") + connection->qtDbString(cbQuote->GetValue()); if (connection->BackendMinimumVersion(8, 0) && !cbEscape->GetValue().IsEmpty()) query += wxT("ESCAPE ") + connection->qtDbString(cbEscape->GetValue()); if (someColumnsToIgnoreForNulls) query += wxT("FORCE NOT NULL ") + columnsToIgnoreForNulls + wxT(" "); } } // Check CSV file if (!wxFileName::FileExists(pickerImportfile->GetPath())) { wxString msg; msg.Printf(_("The file %s doesn't exist.\nPlease select a valid file."), pickerImportfile->GetPath().c_str()); wxLogError(msg); return; } // Open CSV file fn = wxFileName(pickerImportfile->GetPath()); file = new wxFile(fn.GetFullPath(), wxFile::read); // Set range for gauge gauge->SetRange(file->Length()); // Start COPY if (!connection->StartCopy(query)) { goterror = true; } // Send COPY data while (!copydone && !goterror) { // Read a buffer char *buffer = new char[nCount + 4]; memset(buffer, 0, nCount + 4); off_t len = file->Read(buffer, nCount); // If we read something, send it to the server if (len > 0) { if (!connection->PutCopyData(buffer, len)) { goterror = true; } else { gauge->SetValue(gauge->GetValue() + len); Update(); } } // If we read nothing, we're done copydone = len == 0; // Clean the buffer delete[] buffer; } // Close CSV file file->Close(); // End COPY if (goterror) { connection->EndPutCopy(_("Copy failed!")); } else { goterror = !connection->EndPutCopy(wxT("")); } // Get final status of the COPY command if (!connection->GetCopyFinalStatus()) { goterror = true; } if (goterror) { wxLogError(_("Copy failed!\n") + connection->GetLastError()); } else { btnOK->SetLabel(wxT("Done")); done = true; } } else { Close(); } } importFactory::importFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list) { mnu->Append(id, _("&Import..."), _("Import CSV file into a relation")); } wxWindow *importFactory::StartDialog(frmMain *form, pgObject *obj) { pgDatabase *db = obj->GetDatabase(); wxString applicationname = appearanceFactory->GetLongAppName() + _(" - Import Tool"); pgConn *conn = db->CreateConn(applicationname); if (conn) { frmImport *frm = new frmImport(form, obj, conn); frm->Show(); } return 0; } bool importFactory::CheckEnable(pgObject *obj) { return obj && (obj->IsCreatedBy(tableFactory)||obj->IsCreatedBy(pg_partitionFactory)); }