*** a/pgadmin/ctl/ctlCheckTreeView.cpp --- b/pgadmin/ctl/ctlCheckTreeView.cpp *************** *** 23,28 **** --- 23,29 ---- #include "images/checked.pngc" #include "images/disabled.pngc" #include "images/unchecked.pngc" + #include "frm/pasteTables.h" BEGIN_EVENT_TABLE(ctlCheckTreeView, wxTreeCtrl) EVT_LEFT_DOWN( ctlCheckTreeView::OnLeftClick) *************** *** 30,36 **** END_EVENT_TABLE() ctlCheckTreeView::ctlCheckTreeView(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style) ! : wxTreeCtrl(parent, id, pos, size, style) { wxImageList *treeimages = new wxImageList(16, 16, true, 3); treeimages->Add(*unchecked_png_img); --- 31,37 ---- ctlCheckTreeView::ctlCheckTreeView(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style) ! : wxTreeCtrl(parent, id, pos, size, style), copytables(0) { wxImageList *treeimages = new wxImageList(16, 16, true, 3); treeimages->Add(*unchecked_png_img); *************** *** 46,62 **** void ctlCheckTreeView::OnLeftClick(wxMouseEvent &evt) wxTreeItemId node = HitTest(evt.GetPosition(), flags); int newimage = 0; ! if ((flags & wxTREE_HITTEST_ONITEMLABEL) || (flags & wxTREE_HITTEST_ONITEMICON)) { ! if (GetItemImage(node) == 0) ! newimage = 1; ! else if (GetItemImage(node) == 1) ! newimage = 0; ! if (newimage == 0 || newimage == 1) ! SetParentAndChildImage(node, newimage); ! if (newimage == 1) ! SetParentImage(node, newimage); } evt.Skip(); --- 47,145 ---- wxTreeItemId node = HitTest(evt.GetPosition(), flags); int newimage = 0; ! if (copytables) { ! if ((flags & wxTREE_HITTEST_ONITEMLABEL) || (flags & wxTREE_HITTEST_ONITEMICON)) ! { ! if (GetItemImage(node) == 0) ! newimage = 1; ! else if (GetItemImage(node) == 1) ! newimage = 0; ! int level = 0; ! wxTreeItemId parent = GetItemParent(node); ! while (parent) ! { ! level++; ! parent = GetItemParent(parent); ! } ! //level == 0 root(Server Groups) ! //level == 1 group ! //level == 2 server ! //level == 3 db ! //level == 4 schema ! //level == 5 table ! switch (level) ! { ! case 4: ! { ! wxTreeItemIdValue childData; ! wxTreeItemId child = GetFirstChild(node, childData); ! while (child) ! { ! SetItemImage(child, newimage); ! child = GetNextChild(node, childData); ! } ! SetItemImage(node, newimage); ! break; ! } ! case 5: ! SetItemImage(node, newimage); ! break; ! default: ! break; ! } ! if (newimage == 1 && level < 5 && !HasChildren(node)) ! { ! wxTreeItemId servernode, dbnode, schemanode; ! int level1 = level + 1; ! wxString servername, dbname, schemaname; ! parent = node; ! while (parent) ! { ! level1--; ! switch (level1) ! { ! case 2: ! servername = GetItemText(parent); ! servernode = parent; ! break; ! case 3: ! dbname = GetItemText(parent); ! dbnode = parent; ! break; ! case 4: ! schemaname = GetItemText(parent); ! schemanode = parent; ! break; ! default: ! break; ! } ! parent = GetItemParent(parent); ! } ! frmCopyTables *frm = (frmCopyTables *)copytables; ! bool success = frm->treeDetails(servername, dbname, schemaname); ! if (success) ! { ! SetItemImage((dbname.IsEmpty()) ? servernode : (schemaname.IsEmpty()) ? dbnode : schemanode, 0); ! Expand((dbname.IsEmpty()) ? servernode : (schemaname.IsEmpty()) ? dbnode : schemanode); ! } ! } ! } ! } ! else ! { ! if ((flags & wxTREE_HITTEST_ONITEMLABEL) || (flags & wxTREE_HITTEST_ONITEMICON)) ! { ! if (GetItemImage(node) == 0) ! newimage = 1; ! else if (GetItemImage(node) == 1) ! newimage = 0; ! if (newimage == 0 || newimage == 1) ! SetParentAndChildImage(node, newimage); ! if (newimage == 1) ! SetParentImage(node, newimage); ! } } evt.Skip(); *** a/pgadmin/db/pgConn.cpp --- b/pgadmin/db/pgConn.cpp *************** *** 709,714 **** bool pgConn::ExecuteVoid(const wxString &sql, bool reportError) --- 709,743 ---- } + ////////////////////////////////////////////////////////////////////////// + // Execute SQL with optional result set + ////////////////////////////////////////////////////////////////////////// + PGresult * pgConn::ExecuteOptionalResult(const wxString &sql, bool reportError) + { + PGresult *qryRes = 0; + + if (GetStatus() != PGCONN_OK) + return qryRes; + + // Execute the query and get the status. + + + wxLogSql(wxT("Void query (%s:%d): %s"), this->GetHost().c_str(), this->GetPort(), sql.c_str()); + qryRes = PQexec(conn, sql.mb_str(*conv)); + lastResultStatus = PQresultStatus(qryRes); + SetLastResultError(qryRes); + + // Check for errors + if (lastResultStatus != PGRES_COMMAND_OK && lastResultStatus != PGRES_COPY_IN && lastResultStatus != PGRES_COPY_OUT) + { + LogError(!reportError); + PQclear(qryRes); + qryRes = 0; + } + + return qryRes; + } + wxString pgConn::ExecuteScalar(const wxString &sql) { --- 108,113 ---- *** a/pgadmin/frm/events.cpp --- b/pgadmin/frm/events.cpp *************** *** 38,43 **** --- 38,46 ---- #include "schema/pgTable.h" #include "dlg/dlgProperty.h" + // custom events + DEFINE_EVENT_TYPE(EVT_THREAD_COPYPASTE_UPDATE_GUI) + // Event table BEGIN_EVENT_TABLE(frmMain, pgFrame) EVT_CHILD_FOCUS( frmMain::OnChildFocus) *************** *** 73,78 **** BEGIN_EVENT_TABLE(frmMain, pgFrame) --- 76,86 ---- EVT_AUI_PANE_CLOSE( frmMain::OnAuiUpdate) EVT_AUINOTEBOOK_PAGE_CLOSE(wxID_ANY, frmMain::OnAuiNotebookPageClose) + EVT_COMMAND(wxID_ANY, EVT_THREAD_COPYPASTE_UPDATE_GUI, frmMain::OnThreadCopypasteUpdateGUI) + EVT_TREE_BEGIN_DRAG(CTL_BROWSER, frmMain::OnBeginDrag) + EVT_TREE_END_DRAG(CTL_BROWSER, frmMain::OnEndDrag) + + #ifdef __WXGTK__ EVT_TREE_KEY_DOWN(CTL_BROWSER, frmMain::OnTreeKeyDown) #endif *************** *** 147,152 **** void frmMain::OnExit(wxCommandEvent &event) --- 155,180 ---- void frmMain::OnClose(wxCloseEvent &event) { + if (pasteTables::isActive()) + { + pasteTables *copypasteobject = GetCopypasteobject(); + if (copypasteobject) + { + if (wxMessageBox( + _("Paste table(s) is active !\nDo you really want to quit ?\n"), + _("Paste table(s) is active"), wxYES_NO) == wxNO) + { + return; + } + if (copypasteobject->thread) + { + copypasteobject->thread->Delete(); + delete copypasteobject->thread; + copypasteobject->thread = NULL; + } + } + } + wxWindow *fr; windowList::Node *node; while ((node = frames.GetFirst()) != NULL) *** a/pgadmin/frm/frmMain.cpp --- b/pgadmin/frm/frmMain.cpp *************** *** 364,369 **** void frmMain::CreateMenus() --- 364,374 ---- new searchObjectFactory(menuFactories, editMenu, 0); editMenu->AppendSeparator(); + copytablefactory = new copyTableFactory(menuFactories, editMenu, toolBar); + new copyTablesListFactory(menuFactories, editMenu, toolBar); + pastetablesfactory = new pasteTablesFactory(menuFactories, editMenu, toolBar); + editMenu->AppendSeparator(); + new separatorFactory(menuFactories); toolBar->AddSeparator(); *************** *** 840,845 **** bool frmMain::CheckAlive() --- 845,852 ---- browser->DeleteChildren(db->GetId()); db->UpdateIcon(browser); + copyTableFactory::copytObject = NULL; + frmCopyTables::selectedTables.empty(); } else { *************** *** 858,863 **** bool frmMain::CheckAlive() --- 865,872 ---- browser->DeleteChildren(db->GetId()); db->UpdateIcon(browser); + copyTableFactory::copytObject = NULL; + frmCopyTables::selectedTables.empty(); } else // Indicate things are back to normal *************** *** 893,898 **** bool frmMain::CheckAlive() --- 902,909 ---- browser->SelectItem(serverItem); execSelChange(serverItem, true); browser->DeleteChildren(serverItem); + copyTableFactory::copytObject = NULL; + frmCopyTables::selectedTables.empty(); } else { *************** *** 911,916 **** bool frmMain::CheckAlive() --- 922,929 ---- browser->SelectItem(serverItem); execSelChange(serverItem, true); browser->DeleteChildren(serverItem); + copyTableFactory::copytObject = NULL; + frmCopyTables::selectedTables.empty(); } else // Indicate things are back to normal *************** *** 1062,1067 **** int frmMain::ReconnectServer(pgServer *server, bool restore) --- 1075,1081 ---- GetMenuFactories()->CheckMenu((pgObject *)browser->GetItemData(item), GetMenuBar(), (ctlMenuToolbar *)GetToolBar()); else GetMenuFactories()->CheckMenu(server, GetMenuBar(), (ctlMenuToolbar *)GetToolBar()); + browser->SetFocus(); return res; } case PGCONN_DNSERR: *************** *** 1427,1429 **** wxWindow *bugReportFactory::StartDialog(frmMain *form, pgObject *obj) --- 1441,1589 ---- DisplayHelp(wxT("bugreport"), HELP_PGADMIN); return 0; } + + + void frmMain::OnThreadCopypasteUpdateGUI(wxCommandEvent &ev) + { + struct transfer_tag *transfer = (transfer_tag *)ev.GetClientData(); + if (transfer->THIS->thread) + { + transfer->THIS->thread->Delete(); + delete transfer->THIS->thread; + transfer->THIS->thread = NULL; + } + transfer->THIS->commitChanges(); + + int numfiles = transfer->numberOfCopypasteTables; + numfiles--; + if (numfiles < 1 && transfer->targetconn->IsAlive()) + { + wxString pastemsg = wxString::Format(_("%d of %d table(s) copied from %s to %s"), + transfer->THIS->copied, + transfer->THIS->tableCopyPasteArray->Count(), + (frmCopyTables::selectedTables.IsEmpty()) ? + (transfer->srcdatabase->GetQuotedIdentifier() + wxT(".") + transfer->srcschemaname).c_str() : + _("the selection list"), + (transfer->targetdatabase->GetQuotedIdentifier() + wxT(".") + transfer->targetschemaname).c_str()); + if (transfer->THIS->copied && transfer->targetdatabase) + { + pgSchema *targetschema = transfer->THIS->findSchema(this, transfer->targetdatabase, transfer->targetschemaname); + if (targetschema) + { + Refresh(transfer->targetschema); + targetschema = transfer->THIS->findSchema(this, transfer->targetdatabase, transfer->targetschemaname); + if (targetschema) + { + targetschema->ShowTreeDetail(GetBrowser()); + GetMenuFactories()->CheckMenu(targetschema, GetMenuBar(), (ctlMenuToolbar *)GetToolBar()); + } + } + } + GetStatusBar()->SetStatusText(pastemsg, 1); + transfer->THIS->GetFactory()->GetToolbar()->SetToolShortHelp(transfer->THIS->GetFactory()->GetId(), pastemsg); + } + + if (!transfer->targetconn->IsAlive()) + { + copyTableFactory::copytObject = NULL; + frmCopyTables::selectedTables.empty(); + numfiles = -1; + } + + if (transfer->sourceconn->GetDbname() == transfer->targetconn->GetDbname() && + transfer->sourceconn->GetHost() == transfer->targetconn->GetHost() && + transfer->sourceconn->GetPort() == transfer->targetconn->GetPort()) + { + //same DB server + } + else + { + delete transfer->targetconn; + } + delete transfer->sourceconn; + + if (numfiles < 1) + { + transfer->THIS->tableCopyPasteArray->Empty(); + delete transfer->THIS->tableCopyPasteArray; + delete transfer->THIS; + delete transfer; + SetCopypasteobject(NULL); + pasteTables::setActive(false); + return; + } + + transfer->numberOfCopypasteTables = numfiles; + bool OK = transfer->THIS->pasteNextTable(); + + if (OK && !transfer->pastesuccess) + { + if (transfer->THIS->thread) + { + transfer->THIS->thread->Delete(); + transfer->THIS->thread = NULL; + } + if (transfer->sourceconn->GetDbname() == transfer->targetconn->GetDbname() && + transfer->sourceconn->GetHost() == transfer->targetconn->GetHost() && + transfer->sourceconn->GetPort() == transfer->targetconn->GetPort()) + { + //same DB server + } + else + { + delete transfer->targetconn; + } + delete transfer->sourceconn; + transfer->THIS->tableCopyPasteArray->Empty(); + delete transfer->THIS->tableCopyPasteArray; + transfer->THIS->GetFactory()->GetToolbar()->SetToolShortHelp(transfer->THIS->GetFactory()->GetId(), transfer->THIS->lastResultError.formatted_msg); + delete transfer->THIS; + delete transfer; + SetCopypasteobject(NULL); + pasteTables::setActive(false); + } + } + + void frmMain::OnBeginDrag(wxTreeEvent &event) + { + ctlTree *browser = GetBrowser(); + wxTreeItemId item = event.GetItem(); + pgObject *obj = browser->GetObject(item); + + if (!obj || pasteTables::isActive()) + return; + if (obj->GetConnection()) + { + pgTable *table = (obj->GetMetaType() == PGM_TABLE) ? dynamic_cast(obj) : 0; + if (table) + { + m_draggedObject = obj; + event.Allow(); + } + else + { + pgSchema *schema = (obj->GetMetaType() == PGM_SCHEMA) ? dynamic_cast(obj) : 0; + if (schema) + { + m_draggedObject = obj; + event.Allow(); + } + } + } + } + + void frmMain::OnEndDrag(wxTreeEvent &event) + { + pgObject *draggedObject = m_draggedObject; + m_draggedObject = NULL; + ctlTree *browser = GetBrowser(); + wxTreeItemId item = event.GetItem(); + pgObject *dst = browser->GetObject(item); + if (!draggedObject || !dst || pasteTables::isActive()) + return; + pgSchema *schema = (dst->GetMetaType() == PGM_SCHEMA) ? dynamic_cast(dst) : 0; + if (!schema) + return; + copytablefactory->StartDialog(this, draggedObject); + pastetablesfactory->StartDialog(this, dst); + } *** a/pgadmin/frm/module.mk --- b/pgadmin/frm/module.mk *************** *** 33,39 **** pgadmin3_SOURCES += \ $(srcdir)/frm/frmRestore.cpp \ $(srcdir)/frm/frmSplash.cpp \ $(srcdir)/frm/frmStatus.cpp \ ! $(srcdir)/frm/plugins.cpp EXTRA_DIST += \ $(srcdir)/frm/module.mk --- 33,40 ---- $(srcdir)/frm/frmRestore.cpp \ $(srcdir)/frm/frmSplash.cpp \ $(srcdir)/frm/frmStatus.cpp \ ! $(srcdir)/frm/plugins.cpp \ ! $(srcdir)/frm/pasteTables.cpp EXTRA_DIST += \ $(srcdir)/frm/module.mk *** /dev/null --- b/pgadmin/frm/pasteTables.cpp *************** *** 0 **** --- 1,2271 ---- + ////////////////////////////////////////////////////////////////////////// + // + // pgAdmin III - PostgreSQL Tools + // + // Copyright (C) 2002 - 2011, The pgAdmin Development Team + // This software is released under the PostgreSQL Licence + // + // frmPasteObject.cpp - Copy/Paste table(s) functions + // + ////////////////////////////////////////////////////////////////////////// + + // wxWindows headers + #include + + // PostgreSQL headers + #include + + #include "frm/pasteTables.h" + #include "schema/pgColumn.h" + #include "schema/pgSequence.h" + #include "schema/pgIndexConstraint.h" + #include "schema/pgForeignKey.h" + #include "schema/pgCheck.h" + #include "ctl/ctlMenuToolbar.h" + + #include + + #include + WX_DEFINE_OBJARRAY(pgTableCopyPasteArray); + WX_DEFINE_OBJARRAY(selectedTablesArray); + + bool pasteTables::active = false; + struct copy_object_tag *copyTableFactory::copytObject = NULL; + selectedTablesArray frmCopyTables::selectedTables; + + pasteTables::pasteTables(frmMain *form, struct copy_object_tag *sourceobj, pgObject *targetobj, pasteTablesFactory *factory) + { + this->mainform = form; + this->sourceobj= sourceobj; + this->targetobj= targetobj; + this->factory= factory; + } + + bool pasteTables::tableExists(pgSchema *srcschema, wxString &tablename) + { + pgSet *set = srcschema->GetDatabase()->ExecuteSet( + wxT("SELECT tablename\n") + wxT(" FROM pg_tables\n") + wxT(" WHERE schemaname=") + srcschema->qtDbString(srcschema->GetName()) + + wxT(" AND tablename=") + srcschema->qtDbString(tablename)); + if (set) + { + long cnt = set->NumRows(); + delete set; + if (cnt) + return true; + } + return false; + } + + pgTable *pasteTables::findTable(frmMain *frm, pgSchema *srcschema, const wxString &tablename) + { + ctlTree *browser = frm->GetBrowser(); + pgCollection *tables = browser->FindCollection(tableFactory, srcschema->GetId()); + if (tables) + { + pgObject *obj; + pgTable *srctable; + treeObjectIterator colIt(browser, tables); + while ((obj = colIt.GetNextObject()) != 0) { + srctable = (pgTable *)obj; + if (srctable->GetName() == tablename) + return srctable; + } + } + return 0; + } + + pgSchema *pasteTables::findSchema(frmMain *frm, pgDatabase *database, const wxString &schemaname) + { + ctlTree *browser = frm->GetBrowser(); + pgCollection *schemas = browser->FindCollection(schemaFactory, database->GetId()); + if (schemas) + { + pgObject *obj; + pgSchema *srcschema; + treeObjectIterator colIt(browser, schemas); + while ((obj = colIt.GetNextObject()) != 0) { + srcschema = (pgSchema *)obj; + if (srcschema->GetIdentifier() == schemaname) + return srcschema; + } + } + return 0; + } + + pgDatabase *pasteTables::findDB(frmMain *frm, const wxString &groupname, const wxString &servername, const wxString &dbname, bool shouldbeconnected) + { + ctlTree *browser = frm->GetBrowser(); + if (browser->ItemHasChildren(browser->GetRootItem())) + { + wxTreeItemIdValue groupcookie; + wxTreeItemId groupItem = browser->GetFirstChild(browser->GetRootItem(), groupcookie); + while (groupItem) + { + wxCookieType cookie; + wxTreeItemId serverItem = browser->GetFirstChild(groupItem, cookie); + while (serverItem) + { + pgServer *server = (pgServer *)browser->GetObject(serverItem); + if (server && server->IsCreatedBy(serverFactory) && server->connection()) + { + if (server->connection()->IsAlive() && server->GetName() == servername && server->GetGroup() == groupname) + { + wxCookieType cookie2; + wxTreeItemId item = browser->GetFirstChild(serverItem, cookie2); + while (item) + { + pgObject *obj = browser->GetObject(item); + if (obj && obj->IsCreatedBy(databaseFactory.GetCollectionFactory())) + { + wxCookieType cookie3; + item = browser->GetFirstChild(obj->GetId(), cookie3); + while (item) + { + pgDatabase *db = (pgDatabase *)browser->GetObject(item); + if (db && db->IsCreatedBy(databaseFactory)) + { + if (shouldbeconnected) + { + pgConn *conn = db->GetConnection(); + if (conn) + { + if (!(!conn->IsAlive() && (conn->GetStatus() == PGCONN_BROKEN || conn->GetStatus() == PGCONN_BAD))) + { + if (db->GetName() == dbname) + return db; + } + } + } + else + { + if (db->GetName() == dbname) + return db; + } + } + item = browser->GetNextChild(obj->GetId(), cookie3); + } + } + item = browser->GetNextChild(serverItem, cookie2); + } + } + } + serverItem = browser->GetNextChild(groupItem, cookie); + } + groupItem = browser->GetNextChild(browser->GetRootItem(), groupcookie); + } + } + + return 0; + } + pgServer *pasteTables::findServer(frmMain *frm, const wxString &groupname, const wxString &servername) + { + ctlTree *browser = frm->GetBrowser(); + if (browser->ItemHasChildren(browser->GetRootItem())) + { + wxTreeItemIdValue groupcookie; + wxTreeItemId groupItem = browser->GetFirstChild(browser->GetRootItem(), groupcookie); + while (groupItem) + { + wxCookieType cookie; + wxTreeItemId serverItem = browser->GetFirstChild(groupItem, cookie); + while (serverItem) + { + pgServer *server = (pgServer *)browser->GetObject(serverItem); + if (server && server->IsCreatedBy(serverFactory)) + { + if (server->GetDescription() == servername && server->GetGroup() == groupname) + { + return server; + } + } + serverItem = browser->GetNextChild(groupItem, cookie); + } + groupItem = browser->GetNextChild(browser->GetRootItem(), groupcookie); + } + } + + return 0; + } + + void pasteTables::GetLastResultError(pgConn *conn, PGresult *res, const wxString &msg) + { + if (res) + { + lastResultError.severity = wxString(PQresultErrorField(res, PG_DIAG_SEVERITY), *conn->GetConv()); + lastResultError.sql_state = wxString(PQresultErrorField(res, PG_DIAG_SQLSTATE), *conn->GetConv()); + lastResultError.msg_primary = wxString(PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY), *conn->GetConv()); + lastResultError.msg_detail = wxString(PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL), *conn->GetConv()); + lastResultError.msg_hint = wxString(PQresultErrorField(res, PG_DIAG_MESSAGE_HINT), *conn->GetConv()); + lastResultError.statement_pos = wxString(PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION), *conn->GetConv()); + lastResultError.internal_pos = wxString(PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION), *conn->GetConv()); + lastResultError.internal_query = wxString(PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY), *conn->GetConv()); + lastResultError.context = wxString(PQresultErrorField(res, PG_DIAG_CONTEXT), *conn->GetConv()); + lastResultError.source_file = wxString(PQresultErrorField(res, PG_DIAG_SOURCE_FILE), *conn->GetConv()); + lastResultError.source_line = wxString(PQresultErrorField(res, PG_DIAG_SOURCE_LINE), *conn->GetConv()); + lastResultError.source_function = wxString(PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION), *conn->GetConv()); + } + else + { + lastResultError.severity = wxEmptyString; + lastResultError.sql_state = wxEmptyString; + if (msg.IsEmpty()) + lastResultError.msg_primary = conn->GetLastError(); + else + lastResultError.msg_primary = msg; + lastResultError.msg_detail = wxEmptyString; + lastResultError.msg_hint = wxEmptyString; + lastResultError.statement_pos = wxEmptyString; + lastResultError.internal_pos = wxEmptyString; + lastResultError.internal_query = wxEmptyString; + lastResultError.context = wxEmptyString; + lastResultError.source_file = wxEmptyString; + lastResultError.source_line = wxEmptyString; + lastResultError.source_function = wxEmptyString; + } + + wxString errMsg; + + if (lastResultError.severity != wxEmptyString && lastResultError.msg_primary != wxEmptyString) + errMsg = lastResultError.severity + wxT(": ") + lastResultError.msg_primary; + else if (lastResultError.msg_primary != wxEmptyString) + errMsg = lastResultError.msg_primary; + + if (!lastResultError.sql_state.IsEmpty()) + { + if (!errMsg.EndsWith(wxT("\n"))) + errMsg += wxT("\n"); + errMsg += _("SQL state: "); + errMsg += lastResultError.sql_state; + } + + if (!lastResultError.msg_detail.IsEmpty()) + { + if (!errMsg.EndsWith(wxT("\n"))) + errMsg += wxT("\n"); + errMsg += _("Detail: "); + errMsg += lastResultError.msg_detail; + } + + if (!lastResultError.msg_hint.IsEmpty()) + { + if (!errMsg.EndsWith(wxT("\n"))) + errMsg += wxT("\n"); + errMsg += _("Hint: "); + errMsg += lastResultError.msg_hint; + } + + if (!lastResultError.statement_pos.IsEmpty()) + { + if (!errMsg.EndsWith(wxT("\n"))) + errMsg += wxT("\n"); + errMsg += _("Character: "); + errMsg += lastResultError.statement_pos; + } + + if (!lastResultError.context.IsEmpty()) + { + if (!errMsg.EndsWith(wxT("\n"))) + errMsg += wxT("\n"); + errMsg += _("Context: "); + errMsg += lastResultError.context; + } + lastResultError.formatted_msg = errMsg; + } + + /* + * Functions for handling COPY IN/OUT data transfer-> + * + * If you want to use COPY TO STDOUT/FROM STDIN in your application, + * this is the code to steal ;) + */ + + /* + * handleCopyOut + * receives data as a result of a COPY ... TO STDOUT command + * + * conn should be a database connection that you just issued COPY TO on + * and got back a PGRES_COPY_OUT result. + * copystream is the file stream for the data to go to. + * + * result is true if successful, false if not. + */ + void pasteTables::handleCopyOut(pgConn *conn, wxFile & copystream) + { + bool OK = true; + char *buf; + int ret; + PGresult *res; + int counter = 0; + + lastResultError.formatted_msg = wxT(""); + for (;;) + { + counter++; + if (counter % 100) + { + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + break; + } + ret = PQgetCopyData(conn->connection(), &buf, 0); + + if (ret < 0) + break; /* done or error */ + + if (buf) + { + int n = copystream.Write(wxString(buf, wxConvUTF8)); + if (n != 1) + { + if (OK) /* complain only once, keep reading data */ + lastResultError.formatted_msg.Format(_("could not write COPY data: %s\n"), strerror(errno)); + OK = false; + } + PQfreemem(buf); + } + } + + if (OK && !copystream.Flush()) + { + lastResultError.formatted_msg.Format(_("could not write COPY data: %s\n"), strerror(errno)); + OK = false; + } + + if (ret == -2) + { + lastResultError.formatted_msg.Format(_("COPY data transfer failed: %s"), PQerrorMessage(conn->connection())); + OK = false; + } + + /* Check command status and return to normal libpq state */ + res = PQgetResult(conn->connection()); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + if (lastResultError.formatted_msg.IsEmpty()) { + GetLastResultError(conn, res); + } + OK = false; + } + PQclear(res); + } + + /* + * handleCopyIn + * sends data to complete a COPY ... FROM STDIN command + * + * conn should be a database connection that you just issued COPY FROM on + * and got back a PGRES_COPY_IN result. + * copystream is the file stream to read the data from. + * isbinary can be set from PQbinaryTuples(). + * + * result is true if successful, false if not. + */ + + /* read chunk size for COPY IN - size is not critical */ + #define COPYBUFSIZ 8192 + + void pasteTables::handleCopyIn(pgConn *conn, wxFile & copystream, bool isbinary) + { + bool OK; + char buf[COPYBUFSIZ]; + PGresult *res; + int counter = 0; + + OK = true; + + if (isbinary) + { + for (;;) + { + counter++; + if (counter % 100) + { + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + break; + } + int buflen;; + buflen = copystream.Read(buf, 1); + if (buflen <= 0) + break; + if (PQputCopyData(conn->connection(), buf, buflen) <= 0) + { + OK = false; + break; + } + } + } + else + { + wxFileInputStream input(copystream); + wxTextInputStream textfile(input); + + while (input.CanRead()) /* for each bufferload in line ... */ + { + counter++; + if (counter % 100) + { + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + break; + } + wxString buf1 = textfile.ReadLine() + wxT("\n"); + int buflen = buf1.Length(); + if (buf1 == wxT("\n")) + { + break; + } + const wxCharBuffer wc = buf1.ToUTF8(); + const char *tmp = wc.data(); + int lenc = strlen(tmp); + if (PQputCopyData(conn->connection(), tmp, lenc) <= 0) + { + OK = false; + break; + } + } + } + + /* Terminate data transfer */ + const char *errmsg = "aborted because of read failure"; + if (PQputCopyEnd(conn->connection(), OK ? NULL : errmsg) <= 0) + OK = false; + + /* Check command status and return to normal libpq state */ + res = PQgetResult(conn->connection()); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + GetLastResultError(conn, res); + OK = false; + } + PQclear(res); + } + + /* + * Execute a \copy command (frontend copy). We have to open a file, then + * submit a COPY query to the backend and either feed it data from the + * file or route its response into the file. + */ + void pasteTables::do_copy(pgConn *conn, wxString & sql, wxFile & copystream) + { + PGresult *result; + struct stat st; + + result = conn->ExecuteOptionalResult(sql); + switch (PQresultStatus(result)) + { + case PGRES_COPY_OUT: + handleCopyOut(conn, copystream); + break; + case PGRES_COPY_IN: + handleCopyIn(conn, copystream, PQbinaryTuples(result)); + break; + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + case PGRES_BAD_RESPONSE: + lastResultError.formatted_msg.Format(_("copy error: %s\n%s\n"), PQerrorMessage(conn->connection()), sql.c_str()); + break; + default: + lastResultError.formatted_msg.Format( + _("copy error: unexpected response (%d)\n%s\n"), PQresultStatus(result), sql.c_str()); + break; + } + + PQclear(result); + + /* + * Make sure we have pumped libpq dry of results; else it may still be in + * ASYNC_BUSY state, leading to false readings in, eg, get_prompt(). + */ + while ((result = PQgetResult(conn->connection())) != NULL) + { + lastResultError.formatted_msg.Format(_("copy: unexpected response (%d)\n"), PQresultStatus(result)); + /* if still in COPY IN state, try to get out of it */ + if (PQresultStatus(result) == PGRES_COPY_IN) + PQputCopyEnd(conn->connection(), (const char *)_("trying to exit copy mode")); + PQclear(result); + } + } + + void pasteTables::myLogNotice(const wxChar *szFormat, ...) + { + wxLogLevel savedlogLevel = sysLogger::logLevel; + sysLogger::logLevel = LOG_NOTICE; + va_list argptr; + va_start(argptr, szFormat); + wxVLogNotice(szFormat, argptr); + va_end(argptr); + sysLogger::logLevel = savedlogLevel; + } + + void pasteTables::copyTable(struct transfer_tag *transfer) + { + lastResultError.formatted_msg = wxT(""); + bool rc; + + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + return; + myLogNotice(wxT("CopyPaste=\"\n%s\""), transfer->createsql.c_str()); + rc = transfer->targetconn->ExecuteVoid(transfer->createsql, false); + if (!rc) + { + lastResultError = transfer->targetconn->GetLastResultError(); + lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg; + return; + } + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + return; + if (!transfer->searchPath.IsEmpty()) + { + rc = transfer->targetconn->ExecuteVoid(wxT("SET search_path=") + transfer->searchPath, false); + if (!rc) + { + lastResultError = transfer->targetconn->GetLastResultError(); + lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg; + return; + } + } + + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + return; + if (transfer->sourceconn->GetDbname() == transfer->targetconn->GetDbname() && + transfer->sourceconn->GetHost() == transfer->targetconn->GetHost() && + transfer->sourceconn->GetPort() == transfer->targetconn->GetPort()) + { + //same DB server + wxString tablenamenew = qtIdent(transfer->table->srctablename); + bool addsuffix = (!transfer->table->copysuffix.IsEmpty()); + if (addsuffix) + { + if (tablenamenew.StartsWith(wxT("\""))) + { + tablenamenew = tablenamenew.Mid(1, tablenamenew.length() - 2) + transfer->table->copysuffix; + tablenamenew = wxT("\"") + tablenamenew + wxT("\""); + } + else + { + tablenamenew += transfer->table->copysuffix; + tablenamenew = qtIdent(tablenamenew); + } + } + wxString copysql = + wxT("\nINSERT INTO ") + + qtIdent(transfer->targetschemaname) + wxT(".") + tablenamenew + + wxT(" (SELECT * FROM ") + + qtIdent(transfer->srcschemaname) + wxT(".") + qtIdent(transfer->table->srctablename) + + wxT(")\n\n"); + rc = transfer->targetconn->ExecuteVoid(copysql, false); + if (!rc) + { + lastResultError = transfer->targetconn->GetLastResultError(); + lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg; + return; + } + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + return; + } + else + { + //different DB servers + wxString tmpFilename; + wxFile tmpFile; + tmpFilename = wxFileName::CreateTempFileName(wxT("copytable")); + tmpFile.Open(tmpFilename.c_str(), wxFile::write); + if (!tmpFile.IsOpened()) + { + lastResultError.formatted_msg = _("Can't create temporary file: ") + tmpFilename; + return; + } + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + return; + wxString copysql = + wxT("COPY ") + + qtIdent(transfer->srcschemaname) + wxT(".") + qtIdent(transfer->table->srctablename) + + wxT(" TO STDOUT"); + do_copy(transfer->sourceconn, copysql, tmpFile); + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + return; + if (lastResultError.formatted_msg.IsEmpty()) + { + tmpFile.Close(); + tmpFile.Open(tmpFilename.c_str(), wxFile::read); + if (!tmpFile.IsOpened()) + { + lastResultError.formatted_msg = _("Can't open temporary file: ") + tmpFilename; + wxRemoveFile(tmpFilename); + return; + } + if (transfer->THIS->thread && transfer->THIS->thread->TestDestroy()) + { + wxRemoveFile(tmpFilename); + return; + } + copysql = + wxT("COPY ") + + qtIdent(transfer->targetschemaname) + wxT(".") + + qtIdent(transfer->table->srctablename + transfer->table->copysuffix) + + wxT(" FROM STDIN"); + do_copy(transfer->targetconn, copysql, tmpFile); + } + tmpFile.Close(); + wxRemoveFile(tmpFilename); + } + copied++; + } + + void *copyPasteThread::Entry() + { + if (transfer) + { + if (transfer->THIS) + { + transfer->THIS->copyTable(transfer); + if (!TestDestroy()) + { + wxCommandEvent event(EVT_THREAD_COPYPASTE_UPDATE_GUI); + event.SetClientData(transfer); + wxPostEvent(winMain->GetEventHandler(), event); + } + } + } + return(NULL); + } + + int pasteTables::process() + { + if (!sourceobj || !targetobj) + { + return 0; + } + + pgSchema *targetschema = (pgSchema *)targetobj; + + pgDatabase *db = pasteTables::findDB(mainform, sourceobj->groupname, sourceobj->servername, sourceobj->dbname); + if (!db) + return 0; + pgSchema *srcschema = pasteTables::findSchema(mainform, db, sourceobj->schemaname); + if (!srcschema) + return 0; + pgTable *table = pasteTables::findTable(mainform, srcschema, sourceobj->tablename); + + pgConn *sourceconn; + pgConn *targetconn = targetobj->GetConnection(); + + if (table) + { + if (wxMessageBox( + _("Paste source table ?\n") + + table->GetSchema()->GetDatabase()->GetQuotedIdentifier() + wxT(".") + table->GetSchema()->GetQuotedIdentifier() + + wxT(".") + table->GetQuotedIdentifier() + wxT("\n") + + wxT(" into schema\n") + targetschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + + targetschema->GetQuotedIdentifier(), _("Paste table"), wxYES_NO) == wxNO) + { + return 0; + } + srcschema = table->GetSchema(); + sourceconn = table->GetConnection(); + } + else + { + if (wxMessageBox( + _("Paste schema tables ?\n") + + srcschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + srcschema->GetQuotedIdentifier() + wxT("\n") + + wxT(" into schema\n") + + targetschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + targetschema->GetQuotedIdentifier(), + _("Paste schema tables"), wxYES_NO) == wxNO) + { + return 0; + } + sourceconn = srcschema->GetConnection(); + } + + if (!sourceconn || !targetconn) + { + wxMessageBox( + _("Both source and target schema connections should be established before paste table(s) operation !")); + return 0; + } + + static wxString copysuffix = wxT("_copy_1"); + wxString tmpcopysuffix; + if (srcschema->GetId() == targetschema->GetId()) + { + copysuffix = wxGetTextFromUser( + _("Target schema is the same as source schema.\n" + "Enter suffix name for all the new table objects"), + _("New Suffix Name"), + copysuffix); + if (copysuffix.IsEmpty()) + { + copysuffix = wxT("_copy_1"); + return 0; + } + tmpcopysuffix = copysuffix; + } + + ctlTree *browser = mainform->GetBrowser(); + srcschema->ShowTreeDetail(browser); + targetschema->ShowTreeDetail(browser); + tableCopyPasteArray = new pgTableCopyPasteArray(); + pgTableCopyPaste *tablenew; + pgCollection *tables = browser->FindCollection(tableFactory, srcschema->GetId()); + pgCollection *sequences = browser->FindCollection(sequenceFactory, srcschema->GetId()); + + if (table) + { + table->ShowTreeDetail(browser); + pgCollection *constraints = browser->FindCollection(primaryKeyFactory, table->GetId()); + if (constraints) + { + constraints->ShowTreeDetail(browser); + treeObjectIterator consIt(browser, constraints); + pgObject *data; + while ((data = consIt.GetNextObject()) != 0) + { + data->ShowTreeDetail(browser); + } + } + pgCollection *columns = browser->FindCollection(columnFactory, table->GetId()); + if (columns) + columns->ShowTreeDetail(browser); + tablenew = new pgTableCopyPaste(table, targetschema, tmpcopysuffix, columns, constraints, tables, sequences); + tablenew->srcgroupname = table->GetServer()->GetGroup(); + tablenew->srcservername = table->GetServer()->GetName(); + tablenew->srcdbname = table->GetDatabase()->GetName(); + tablenew->srctablename = table->GetName(); + tablenew->targetgroupname = targetschema->GetServer()->GetGroup(); + tablenew->targetservername = targetschema->GetServer()->GetName(); + tablenew->targetdbname = targetschema->GetDatabase()->GetName(); + tableCopyPasteArray->Add(tablenew); + } + else + { + if (tables) + { + pgObject *obj; + pgTable *srctable; + treeObjectIterator colIt(browser, tables); + while ((obj = colIt.GetNextObject()) != 0) { + srctable = (pgTable *)obj; + srctable->ShowTreeDetail(browser); + pgCollection *constraints = browser->FindCollection(primaryKeyFactory, srctable->GetId()); + if (constraints) + { + constraints->ShowTreeDetail(browser); + treeObjectIterator consIt(browser, constraints); + pgObject *data; + while ((data = consIt.GetNextObject()) != 0) + { + data->ShowTreeDetail(browser); + } + } + pgCollection *columns = browser->FindCollection(columnFactory, srctable->GetId()); + if (columns) + columns->ShowTreeDetail(browser); + tablenew = new pgTableCopyPaste(srctable, targetschema, tmpcopysuffix, columns, constraints, tables, sequences); + tablenew->srcgroupname = srctable->GetServer()->GetGroup(); + tablenew->srcservername = srctable->GetServer()->GetName(); + tablenew->srcdbname = srctable->GetDatabase()->GetName(); + tablenew->srctablename = srctable->GetName(); + tablenew->targetgroupname = targetschema->GetServer()->GetGroup(); + tablenew->targetservername = targetschema->GetServer()->GetName(); + tablenew->targetdbname = targetschema->GetDatabase()->GetName(); + tableCopyPasteArray->Add(tablenew); + } + } + } + + transfer = new struct transfer_tag(); + + transfer->THIS = this; + transfer->THIS->thread = NULL; + transfer->targetdatabase = targetschema->GetDatabase(); + transfer->targetschemaname = targetschema->GetIdentifier(); + transfer->numberOfCopypasteTables = tableCopyPasteArray->Count(); + copied = 0; + pasteNextTable(); + return tableCopyPasteArray->Count(); + } + + int pasteTables::processListOfTables() + { + if (frmCopyTables::selectedTables.IsEmpty() || !targetobj) + { + return 0; + } + + pgSchema *targetschema = (pgSchema *)targetobj; + pgDatabase *db; + pgSchema *srcschema; + pgTable *table; + pgConn *targetconn = targetobj->GetConnection(); + + if (wxMessageBox( + _("Paste tables from the selection list ?\n into schema\n") + + targetschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + targetschema->GetQuotedIdentifier(), + _("Paste tables from the selection list"), wxYES_NO) == wxNO) + { + return 0; + } + + if (!targetconn) + { + wxMessageBox( + _("Target schema connection should be established before paste table(s) operation !")); + return 0; + } + + wxString copysuffix; + + ctlTree *browser = mainform->GetBrowser(); + targetschema->ShowTreeDetail(browser); + tableCopyPasteArray = new pgTableCopyPasteArray(); + pgTableCopyPaste *tablenew; + struct copy_object_tag item; + + for (unsigned int i = 0; i < frmCopyTables::selectedTables.Count(); i++) + { + item = frmCopyTables::selectedTables.Item(i); + db = pasteTables::findDB(mainform, item.groupname, item.servername, item.dbname); + if (!db) + continue; + srcschema = pasteTables::findSchema(mainform, db, item.schemaname); + if (!srcschema) + continue; + table = pasteTables::findTable(mainform, srcschema, item.tablename); + if (!table) + continue; + table->ShowTreeDetail(browser); + pgCollection *constraints = browser->FindCollection(primaryKeyFactory, table->GetId()); + if (constraints) + { + constraints->ShowTreeDetail(browser); + treeObjectIterator consIt(browser, constraints); + pgObject *data; + while ((data = consIt.GetNextObject()) != 0) + { + data->ShowTreeDetail(browser); + } + } + pgCollection *tables = browser->FindCollection(tableFactory, table->GetSchema()->GetId()); + pgCollection *sequences = browser->FindCollection(sequenceFactory, table->GetSchema()->GetId()); + pgCollection *columns = browser->FindCollection(columnFactory, table->GetId()); + if (columns) + columns->ShowTreeDetail(browser); + tablenew = new pgTableCopyPaste(table, targetschema, copysuffix, columns, constraints, tables, sequences); + tablenew->srcgroupname = table->GetServer()->GetGroup(); + tablenew->srcservername = table->GetServer()->GetName(); + tablenew->srcdbname = table->GetDatabase()->GetName(); + tablenew->srctablename = table->GetName(); + tablenew->targetgroupname = targetschema->GetServer()->GetGroup(); + tablenew->targetservername = targetschema->GetServer()->GetName(); + tablenew->targetdbname = targetschema->GetDatabase()->GetName(); + tableCopyPasteArray->Add(tablenew); + } + + transfer = new struct transfer_tag(); + + transfer->THIS = this; + transfer->THIS->thread = NULL; + transfer->targetdatabase = targetschema->GetDatabase(); + transfer->targetschemaname = targetschema->GetIdentifier(); + transfer->numberOfCopypasteTables = tableCopyPasteArray->Count(); + + copied = 0; + pasteNextTable(); + return tableCopyPasteArray->Count(); + } + + bool pasteTables::pasteNextTable() + { + int i = transfer->numberOfCopypasteTables - 1; + ctlTree *browser = mainform->GetBrowser(); + bool err = false; + pgTableCopyPaste &item = tableCopyPasteArray->Item(i); + transfer->srcdatabase = item.Getsrctable()->GetDatabase(); + transfer->srcschemaname = item.Getsrctable()->GetSchema()->GetIdentifier(); + + pgDatabase *dbt = pasteTables::findDB(mainform, item.srcgroupname, item.srcservername, item.srcdbname); + if (dbt) + { + if (dbt->GetConnected()) + { + pgSchema *schema = pasteTables::findSchema(mainform, dbt, transfer->srcschemaname); + if (schema) + { + pgTable *table = pasteTables::findTable(mainform, schema, item.srctablename); + if (table == 0) + err = true; + } + else + err = true; + } + else + err = true; + } + else + err = true; + + if (!err) + { + pgDatabase *dbt = pasteTables::findDB(mainform, item.targetgroupname, item.targetservername, item.targetdbname); + if (dbt) + { + if (dbt->GetConnected()) + { + pgSchema *schema = pasteTables::findSchema(mainform, dbt, transfer->targetschemaname); + if (!schema) + err = true; + } + else + err = true; + } + else + err = true; + } + + if (err) + { + lastResultError.formatted_msg = pastemsg + wxT("\n") + + _("Source/Target schema disappeared\nProbably DB server stopped or schema deleted !"); + wxMessageBox(lastResultError.formatted_msg); + if (transfer->THIS->thread) + { + transfer->THIS->thread->Delete(); + transfer->THIS->thread = NULL; + } + transfer->THIS->tableCopyPasteArray->Empty(); + delete transfer->THIS->tableCopyPasteArray; + transfer->THIS->GetFactory()->GetToolbar()->SetToolShortHelp(transfer->THIS->GetFactory()->GetId(), transfer->THIS->lastResultError.formatted_msg); + delete transfer; + mainform->SetCopypasteobject(NULL); + pasteTables::setActive(false); + return false; + } + + transfer->table = &item; + transfer->srcdatabase = item.Getsrctable()->GetDatabase(); + transfer->srcschemaname = item.Getsrctable()->GetSchema()->GetIdentifier(); + transfer->pastesuccess = true; + transfer->THIS->thread = NULL; + wxString targetdatabasename = transfer->targetdatabase->GetQuotedIdentifier(); + wxString srcdatabasename = transfer->srcdatabase->GetQuotedIdentifier(); + + pgConn *targetconn = targetobj->GetConnection(); + pgConn *newtargetconn; + pgConn *newsourceconn = item.Getsrctable()->GetConnection()->Duplicate(); + if (newsourceconn->GetDbname() == targetconn->GetDbname() && + newsourceconn->GetHost() == targetconn->GetHost() && + newsourceconn->GetPort() == targetconn->GetPort()) + { + //same DB server + newtargetconn = newsourceconn; + } + else + { + newtargetconn = targetconn->Duplicate(); + } + + transfer->sourceconn = newsourceconn; + transfer->targetconn = newtargetconn; + + wxString pastemsg1 = _("Copy table:") + + srcdatabasename + wxT(".") + qtIdent(transfer->srcschemaname) + wxT(".") + + item.srctablename + + _(" INTO:") + targetdatabasename + wxT(".") + qtIdent(transfer->targetschemaname); + mainform->GetStatusBar()->SetStatusText(pastemsg1, 1); + pastemsg = _("copy table:\n") + + srcdatabasename + wxT(".") + qtIdent(transfer->srcschemaname) + wxT(".") + + item.srctablename + + _("\nINTO:\n") + targetdatabasename + wxT(".") + qtIdent(transfer->targetschemaname); + + factory->GetToolbar()->SetToolShortHelp(factory->GetId(), pastemsg); + + thread = new copyPasteThread(transfer); + wxThreadError rc = thread->Create(); + + if (rc != wxTHREAD_NO_ERROR) + { + lastResultError.formatted_msg.Format(_("Create thread error: rc=%d\n"), rc); + } + else + { + transfer->srcschema = findSchema(mainform, transfer->srcdatabase, transfer->srcschemaname); + if (!transfer->srcschema) + { + lastResultError.formatted_msg = pastemsg + wxT("\n") + _("Source schema disappeared"); + err = true; + } + if (!err) + { + transfer->targetschema = findSchema(mainform, transfer->targetdatabase, transfer->targetschemaname); + if (!transfer->targetschema) + { + lastResultError.formatted_msg = pastemsg + wxT("\n") + _("Target schema disappeared"); + err = true; + } + } + + if (!err /*&& transfer->srcschema->GetId() != transfer->targetschema->GetId()*/) + { + static wxString copysuffix = wxT("_1"); + wxString tmpcopysuffix; + err = true; + wxString tablename = item.Getsrctable()->GetName() + item.copysuffix; + while (err) + { + err = tableExists(transfer->targetschema, tablename); + if (err) + { + wxString msg = wxString::Format( + _("Target schema %s.%s\n" + "Already contains table %s\n" + "Enter suffix name for the new table objects"), + transfer->targetschema->GetDatabase()->GetName().c_str(), transfer->targetschema->GetName().c_str(), + tablename.c_str()); + copysuffix = wxGetTextFromUser( + msg, + _("New Suffix Name"), + copysuffix); + if (copysuffix.IsEmpty()) + { + pastemsg1 += _(" Canceled by user"); + mainform->GetStatusBar()->SetStatusText(pastemsg1, 1); + copysuffix = wxT("_1"); + + //skip this table + transfer->THIS->thread = NULL; + transfer->numberOfCopypasteTables--; + wxCommandEvent event(EVT_THREAD_COPYPASTE_UPDATE_GUI); + event.SetClientData(transfer); + wxPostEvent(winMain->GetEventHandler(), event); + + return true; + } + tmpcopysuffix = copysuffix; + tablename = item.Getsrctable()->GetName() + item.copysuffix + copysuffix; + } + } + if (!err) + item.copysuffix += tmpcopysuffix; + } + if (!err) + { + bool rc = transfer->targetconn->ExecuteVoid(wxT("BEGIN")); + if (!rc) + { + lastResultError = transfer->targetconn->GetLastResultError(); + lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg; + } + else + { + transfer->createsql = transfer->table->GetSql(browser); + transfer->searchPath = transfer->targetconn->ExecuteScalar(wxT("SHOW search_path")); + transfer->createsql = wxT("SET search_path=") + transfer->targetschema->GetQuotedIdentifier() + + wxT(";\n") + transfer->createsql; + thread->Run(); + return true; + } + } + } + commitChanges(); + return true; + } + + void pasteTables::commitChanges() + { + wxString msg; + if (lastResultError.formatted_msg != wxT("TABLE EXISTS")) + { + if (lastResultError.formatted_msg.IsEmpty()) + { + if (transfer->targetconn->IsAlive()) + { + transfer->targetconn->ExecuteVoid(wxT("COMMIT")); + lastResultError = transfer->targetconn->GetLastResultError(); + if (!lastResultError.formatted_msg.IsEmpty()) + { + lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg; + msg = lastResultError.formatted_msg; + } + } + else + lastResultError.formatted_msg = _("Server closed the connection unexpectedly"); + } + else + { + if (transfer->targetconn->IsAlive()) + { + transfer->targetconn->ExecuteVoid(wxT("ROLLBACK")); + } + msg = lastResultError.formatted_msg; + } + } + if (!lastResultError.formatted_msg.IsEmpty()) + { + transfer->pastesuccess = false; + wxMessageBox(msg, + _("Cannot paste table:") + + transfer->targetdatabase->GetQuotedIdentifier() + wxT(".") + transfer->targetschemaname + + wxT(".") + transfer->table->Getsrctable()->GetQuotedIdentifier(), + wxOK | wxICON_ERROR, winMain); + } + } + + pasteTables::~pasteTables() + { + } + + pgTableCopyPaste::pgTableCopyPaste(pgTable *srctable, pgSchema *targetschema, const wxString ©suffix1, + pgCollection *columns1, pgCollection *constraints1, pgCollection *tables1, pgCollection *sequences1) + { + this->srctable = srctable; + this->targetschema = targetschema; + this->copysuffix = copysuffix1; + this->columns = columns1; + this->constraints = constraints1; + this->tables = tables1; + this->sequences = sequences1; + } + + wxString pgTableCopyPaste::GetSequenceName(const wxString &definition, bool schemaonly) + { + //Supported formats: + //1. nextval('"""".id_gk_vrsta_naloga'::regclass) + //2. nextval(('ps_nalog_id_seq'::text)::regclass) + + //Schema and sequence name combinations: + //1. "schema.name"."seq.name" + //2. "schema.name".seq_name + //3 schema_name."seq.name" + //4 schema_name.seq_name + //5 "seq.name" + //6 seq_name + + wxString defval = definition; + wxString schemaname, seqname; + int pos = wxString(wxT("nextval(")).length(); + if (wxString(defval[pos]) == wxT("(")) + { + pos++; //skip left brace + } + pos++; //skip starting apostrophe + if (wxString(defval[pos]) == wxT("\"")) + { + //start parsing after the first " + wxString newdefval = defval.Mid(pos + 1); + //eliminate Ambiguous ". from the definition field + newdefval.Replace(wxT("\"\""), wxT(" "), true); + + int subseq = newdefval.Find(wxT("\".")); + if (subseq == wxNOT_FOUND) + { + //case 5 quoted sequence name without schema name + subseq = newdefval.rfind(wxT("\"'")); + if (subseq == wxNOT_FOUND) + return wxEmptyString; + schemaname = wxT("public"); + seqname = defval.Mid(pos, subseq + 2); + } + else + { + //quoted schema name + schemaname = defval.Mid(pos + 1, subseq); + schemaname.Replace(wxT("\"\""), wxT("\""), true); + schemaname = wxT("\"") + schemaname + wxT("\""); + subseq += 3; + int subseq1 = newdefval.Mid(subseq + 2).rfind(wxT("'")); + if (subseq1 == wxNOT_FOUND) + return wxEmptyString; + //case 1, 2 quoted schema name + seqname = defval.Mid(pos + subseq, subseq1 + 3); + } + if (wxString(seqname[0]) == wxT("\"")) + { + seqname = seqname.Mid(1, seqname.length() - 2); + seqname.Replace(wxT("\"\""), wxT("\""), true); + seqname.Replace(wxT("''"), wxT("'"), true); + seqname = wxT("\"") + seqname + wxT("\""); + } + } + else + { + //case 3, 4, 5, 6 not quoted schema name + wxString newdefval = defval.Mid(pos); + int subseq = newdefval.Find(wxT(".")); + if (subseq == wxNOT_FOUND) + { + //case 5, 6 sequence name without schema name + subseq = newdefval.rfind(wxT("'")); + if (subseq == wxNOT_FOUND) + return wxEmptyString; + schemaname = wxT("public"); + seqname = defval.Mid(pos, subseq); + } + else + { + //case 3, 4 not quoted schema name + schemaname = defval.Mid(pos, subseq); + subseq += 1; + int subseq1 = newdefval.Mid(subseq + 1).rfind(wxT("'")); + if (subseq1 == wxNOT_FOUND) + return wxEmptyString; + seqname = defval.Mid(pos + subseq, subseq1 + 1); + } + if (wxString(seqname[0]) == wxT("\"")) + { + seqname = seqname.Mid(1, seqname.length() - 2); + seqname.Replace(wxT("\"\""), wxT("\""), true); + seqname.Replace(wxT("''"), wxT("'"), true); + seqname = wxT("\"") + seqname + wxT("\""); + } + } + + return (schemaonly) ? schemaname : seqname; + } + + wxString pgTableCopyPaste::GetSql(ctlTree *browser) + { + wxString colDetails, conDetails; + wxString prevComment; + wxString cols_sql; + wxString sql; + wxString sqlcreate; + wxString sqlsequence = wxT("\n"); + wxString columnPrivileges; + wxString newtablename; + wxString qtfullident; + wxString qtfullidentsrc = srctable->GetQuotedFullIdentifier(); + bool addsuffix = (!copysuffix.IsEmpty()); + + if (addsuffix) + { + newtablename = srctable->GetIdentifier() + copysuffix; + if (!tables) + return sql; + pgObject *obj; + pgTable *srctable; + bool fnd = false; + treeObjectIterator colIt(browser, tables); + while ((obj = colIt.GetNextObject()) != 0) { + srctable = (pgTable *)obj; + if (srctable->GetIdentifier() == newtablename) + { + fnd = true; + break; + } + } + if (!fnd) + { + qtfullident = targetschema->GetQuotedPrefix() + qtIdent(newtablename); + } + } + else + { + qtfullident = targetschema->GetQuotedPrefix() + srctable->GetQuotedIdentifier(); + } + + sqlcreate = wxT("-- Table: ") + qtfullident + wxT("\n\n") + + wxT("-- DROP TABLE ") + qtfullident + wxT(";"); + sql = wxT("\n\nCREATE "); + if (srctable->GetUnlogged()) + sql += wxT("UNLOGGED "); + sql += wxT("TABLE ") + qtfullident; + + // of type (9.0 material) + if (srctable->GetOfTypeOid() > 0) + sql += wxT("\nOF ") + qtIdent(srctable->GetOfType()); + + // Get a count of the constraints. + int consCount = 0; + if (constraints) + consCount = browser->GetChildrenCount(constraints->GetId()); + + // Get the columns + if (columns) + { + treeObjectIterator colIt1(browser, columns); + treeObjectIterator colIt2(browser, columns); + + int lastRealCol = 0; + int currentCol = 0; + pgColumn *column; + + // Iterate the columns to find the last 'real' one + while ((column = (pgColumn *) colIt1.GetNextObject()) != 0) + { + currentCol++; + + if (column->GetInheritedCount() == 0) + lastRealCol = currentCol; + } + + // Now build the actual column list + int colCount = 0; + while ((column = (pgColumn *) colIt2.GetNextObject()) != 0) + { + if (column->GetColNumber() > 0) + { + if (colCount) + { + // Only add a comma if this isn't the last 'real' column, or if there are constraints + if (colCount != lastRealCol || consCount) + cols_sql += wxT(","); + if (!prevComment.IsEmpty()) + cols_sql += wxT(" -- ") + firstLineOnly(prevComment); + + cols_sql += wxT("\n"); + } + + if (column->GetInheritedCount() > 0) + { + if (!column->GetIsLocal()) + { + cols_sql += wxString::Format(wxT("-- %s "), _("Inherited")) + + wxT("from table ") + column->GetInheritedTableName() + wxT(":"); + } + } + + if (srctable->GetOfTypeOid() > 0) + { + if (column->GetDefinition().Length() == 0) + { + cols_sql += wxString::Format(wxT("-- %s "), _("Inherited")) + + wxT("from type ") + srctable->GetOfType() + wxT(": ") + + column->GetQuotedIdentifier(); + } + else + { + cols_sql += wxT(" ") + column->GetQuotedIdentifier() + wxT(" WITH OPTIONS ") + + column->GetDefinition(); + } + } + else + { + wxString coldef = column->GetDefault(); + wxString colseq = column->GetSerialSequence(); + if (colseq.IsEmpty() && coldef.StartsWith(wxT("nextval("))) + { + wxString newseqname, origseqname; + bool fnd = false; + wxString seqname = GetSequenceName(coldef, false); + if (!seqname.IsEmpty()) + { + bool addsuffix = (!copysuffix.IsEmpty()); + if (addsuffix) + { + if (!sequences) + return sql; + pgObject *obj; + pgSequence *srcsequence = 0, *tmpsequence; + bool fnd = false; + newseqname = origseqname = seqname; + if (seqname.StartsWith(wxT("\""))) + { + newseqname = seqname.Mid(1, seqname.length() - 2); + origseqname = seqname.Mid(1, seqname.length() - 2); + } + newseqname += copysuffix; + treeObjectIterator colIt(browser, sequences); + while ((obj = colIt.GetNextObject()) != 0) { + tmpsequence = (pgSequence *)obj; + if (tmpsequence->GetIdentifier() == newseqname) + { + fnd = true; + break; + } + if (tmpsequence->GetIdentifier() == origseqname) + { + srcsequence = tmpsequence; + } + } + if (fnd) + return sql; + pgSequenceCopyPaste seqcp(srcsequence, targetschema, copysuffix); + sqlsequence += seqcp.GetSql(browser); + wxString schseqname = GetSequenceName(coldef, true); + if (schseqname.StartsWith(wxT("\""))) + { + schseqname = schseqname.Mid(1, schseqname.length() - 2); + } + wxString coldef = column->GetDefinition(); + newseqname = qtIdent(newseqname); + wxString qtfullidentseq = targetschema->GetQuotedPrefix() + newseqname; + qtfullidentseq.Replace(wxT("'"), wxT("''")); + origseqname.Replace(wxT("'"), wxT("''")); + int noc = coldef.Replace(qtIdent(schseqname) + wxT(".") + qtIdent(origseqname), qtfullidentseq, true); + if (noc == 0 && schseqname == wxT("public")) + { + coldef.Replace(qtIdent(origseqname), qtfullidentseq, true); + } + cols_sql += wxT(" ") + column->GetQuotedIdentifier() + wxT(" ") + coldef; + } + else + { + if (!tables) + return sql; + pgObject *obj; + pgSequence *srcsequence; + wxString seqname1 = seqname; + if (seqname1.StartsWith(wxT("\""))) + { + seqname1 = seqname1.Mid(1, seqname1.length() - 2); + } + treeObjectIterator colIt(browser, sequences); + while ((obj = colIt.GetNextObject()) != 0) { + srcsequence = (pgSequence *)obj; + if (srcsequence->GetIdentifier() == seqname1) + { + fnd = true; + break; + } + } + if (!fnd) + return sql; + pgSequenceCopyPaste seqcp(srcsequence, targetschema, copysuffix); + sqlsequence += seqcp.GetSql(browser); + wxString schseqname = GetSequenceName(coldef, true); + if (schseqname.StartsWith(wxT("\""))) + { + schseqname = schseqname.Mid(1, schseqname.length() - 2); + } + wxString coldef = column->GetDefinition(); + wxString qtfullidentseq = targetschema->GetQuotedPrefix() + qtIdent(seqname1); + qtfullidentseq.Replace(wxT("'"), wxT("''")); + seqname1.Replace(wxT("'"), wxT("''")); + coldef.Replace(qtIdent(schseqname) + wxT(".") + qtIdent(seqname1), qtfullidentseq, true); + cols_sql += wxT(" ") + column->GetQuotedIdentifier() + wxT(" ") + coldef; + } + } + } + else + cols_sql += wxT(" ") + column->GetQuotedIdentifier() + wxT(" ") + + column->GetDefinition(); + } + + prevComment = column->GetComment(); + + // Whilst we are looping round the columns, grab their comments as well. + wxString comment = column->GetCommentSql(); + comment.Replace(qtfullidentsrc, qtfullident, false); + colDetails += comment; + if (colDetails.Length() > 0) + if (colDetails.Last() != '\n') + colDetails += wxT("\n"); + colDetails += column->GetStorageSql(); + if (colDetails.Length() > 0) + if (colDetails.Last() != '\n') + colDetails += wxT("\n"); + colDetails += column->GetAttstattargetSql(); + if (colDetails.Length() > 0) + if (colDetails.Last() != '\n') + colDetails += wxT("\n"); + + colCount++; + columnPrivileges += column->GetPrivileges(); + } + } + } + + // Now iterate the constraints + if (constraints) + { + wxString constraintname; + treeObjectIterator consIt(browser, constraints); + + pgObject *data; + + while ((data = consIt.GetNextObject()) != 0) + { + cols_sql += wxT(","); + + if (!prevComment.IsEmpty()) + cols_sql += wxT(" -- ") + firstLineOnly(prevComment); + + constraintname = data->GetQuotedIdentifier(); + if (addsuffix) + { + if (constraintname.StartsWith(wxT("\""))) + { + constraintname = constraintname.Mid(1, constraintname.length() - 2) + copysuffix; + constraintname = wxT("\"") + constraintname + wxT("\""); + } + else { + constraintname += copysuffix; + constraintname = qtIdent(constraintname); + } + } + cols_sql += wxT("\n CONSTRAINT ") + constraintname + + wxT(" ") + data->GetTypeName().Upper() + + wxT(" "); + + prevComment = data->GetComment(); + if (!data->GetComment().IsEmpty()) + conDetails += wxT("COMMENT ON CONSTRAINT ") + constraintname + + wxT(" ON ") + srctable->GetQuotedFullIdentifier() + + wxT(" IS ") + srctable->qtDbString(data->GetComment()) + wxT(";\n"); + + switch (data->GetMetaType()) + { + case PGM_PRIMARYKEY: + case PGM_UNIQUE: + case PGM_EXCLUDE: + cols_sql += ((pgIndexConstraint *) data)->GetDefinition(); + break; + case PGM_FOREIGNKEY: + cols_sql += ((pgForeignKey *) data)->GetDefinition(); + break; + case PGM_CHECK: + cols_sql += wxT("(") + ((pgCheck *) data)->GetDefinition() + wxT(")"); + break; + } + } + } + if (!prevComment.IsEmpty()) + cols_sql += wxT(" -- ") + firstLineOnly(prevComment); + + sql += wxT("\n(\n") + cols_sql + wxT("\n)"); + + if (srctable->GetInheritedTableCount()) + { + sql += wxT("\nINHERITS (") + srctable->GetQuotedInheritedTables() + wxT(")"); + } + + if (srctable->GetConnection()->BackendMinimumVersion(8, 2)) + { + sql += wxT("\nWITH ("); + if (srctable->GetFillFactor().Length() > 0) + sql += wxT("\n FILLFACTOR=") + srctable->GetFillFactor() + wxT(", "); + if (srctable->GetAppendOnly().Length() > 0) + sql += wxT("APPENDONLY=") + srctable->GetAppendOnly() + wxT(", "); + if (srctable->GetCompressLevel().Length() > 0) + sql += wxT("COMPRESSLEVEL=") + srctable->GetCompressLevel() + wxT(", "); + if (srctable->GetOrientation().Length() > 0) + sql += wxT("ORIENTATION=") + srctable->GetOrientation() + wxT(", "); + if (srctable->GetCompressType().Length() > 0) + sql += wxT("COMPRESSTYPE=") + srctable->GetCompressType() + wxT(", "); + if (srctable->GetBlocksize().Length() > 0) + sql += wxT("BLOCKSIZE=") + srctable->GetBlocksize() + wxT(", "); + if (srctable->GetChecksum().Length() > 0) + sql += wxT("CHECKSUM=") + srctable->GetChecksum() + wxT(", "); + if (srctable->GetHasOids()) + sql += wxT("\n OIDS=TRUE"); + else + sql += wxT("\n OIDS=FALSE"); + if (srctable->GetConnection()->BackendMinimumVersion(8, 4)) { + if (srctable->GetCustomAutoVacuumEnabled()) { + if (srctable->GetAutoVacuumEnabled() == 1) + sql += wxT(",\n autovacuum_enabled=true"); + else if (srctable->GetCustomAutoVacuumEnabled() == 0) + sql += wxT(",\n autovacuum_enabled=false"); + if (!srctable->GetAutoVacuumVacuumThreshold().IsEmpty()) + { + sql += wxT(",\n autovacuum_vacuum_threshold=") + srctable->GetAutoVacuumVacuumThreshold(); + } + if (!srctable->GetAutoVacuumVacuumScaleFactor().IsEmpty()) + { + sql += wxT(",\n autovacuum_vacuum_scale_factor=") + srctable->GetAutoVacuumVacuumScaleFactor(); + } + if (!srctable->GetAutoVacuumAnalyzeThreshold().IsEmpty()) + { + sql += wxT(",\n autovacuum_analyze_threshold=") + srctable->GetAutoVacuumAnalyzeThreshold(); + } + if (!srctable->GetAutoVacuumAnalyzeScaleFactor().IsEmpty()) + { + sql += wxT(",\n autovacuum_analyze_scale_factor=") + srctable->GetAutoVacuumAnalyzeScaleFactor(); + } + if (!srctable->GetAutoVacuumVacuumCostDelay().IsEmpty()) + { + sql += wxT(",\n autovacuum_vacuum_cost_delay=") + srctable->GetAutoVacuumVacuumCostDelay(); + } + if (!srctable->GetAutoVacuumVacuumCostLimit().IsEmpty()) + { + sql += wxT(",\n autovacuum_vacuum_cost_limit=") + srctable->GetAutoVacuumVacuumCostLimit(); + } + if (!srctable->GetAutoVacuumFreezeMinAge().IsEmpty()) + { + sql += wxT(",\n autovacuum_freeze_min_age=") + srctable->GetAutoVacuumFreezeMinAge(); + } + if (!srctable->GetAutoVacuumFreezeMaxAge().IsEmpty()) + { + sql += wxT(",\n autovacuum_freeze_max_age=") + srctable->GetAutoVacuumFreezeMaxAge(); + } + if (!srctable->GetAutoVacuumFreezeTableAge().IsEmpty()) + { + sql += wxT(",\n autovacuum_freeze_table_age=") + srctable->GetAutoVacuumFreezeTableAge(); + } + } + if (srctable->GetHasToastTable() && srctable->GetToastCustomAutoVacuumEnabled()) + { + if (srctable->GetToastAutoVacuumEnabled() == 1) + sql += wxT(",\n toast.autovacuum_enabled=true"); + else if (srctable->GetToastAutoVacuumEnabled() == 0) + sql += wxT(",\n toast.autovacuum_enabled=false"); + if (!srctable->GetToastAutoVacuumVacuumThreshold().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_vacuum_threshold=") + srctable->GetToastAutoVacuumVacuumThreshold(); + } + if (!srctable->GetToastAutoVacuumVacuumScaleFactor().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_vacuum_scale_factor=") + srctable->GetToastAutoVacuumVacuumScaleFactor(); + } + if (!srctable->GetToastAutoVacuumAnalyzeThreshold().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_analyze_threshold=") + srctable->GetToastAutoVacuumAnalyzeThreshold(); + } + if (!srctable->GetToastAutoVacuumAnalyzeScaleFactor().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_analyze_scale_factor=") + srctable->GetToastAutoVacuumAnalyzeScaleFactor(); + } + if (!srctable->GetToastAutoVacuumVacuumCostDelay().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_vacuum_cost_delay=") + srctable->GetToastAutoVacuumVacuumCostDelay(); + } + if (!srctable->GetToastAutoVacuumVacuumCostLimit().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_vacuum_cost_limit=") + srctable->GetToastAutoVacuumVacuumCostLimit(); + } + if (!srctable->GetToastAutoVacuumFreezeMinAge().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_freeze_min_age=") + srctable->GetToastAutoVacuumFreezeMinAge(); + } + if (!srctable->GetToastAutoVacuumFreezeMaxAge().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_freeze_max_age=") + srctable->GetToastAutoVacuumFreezeMaxAge(); + } + if (!srctable->GetToastAutoVacuumFreezeTableAge().IsEmpty()) + { + sql += wxT(",\n toast.autovacuum_freeze_table_age=") + srctable->GetToastAutoVacuumFreezeTableAge(); + } + } + } + sql += wxT("\n)"); + } + else + { + if (srctable->GetHasOids()) + sql += wxT("\nWITH OIDS"); + else + sql += wxT("\nWITHOUT OIDS"); + } + + if (srctable->GetConnection()->BackendMinimumVersion(8, 0) && + srctable->GetTablespace() != srctable->GetDatabase()->GetDefaultTablespace()) + sql += wxT("\nTABLESPACE ") + qtIdent(srctable->GetTablespace()); + + if (srctable->GetConnection()->GetIsGreenplum()) + { + // Add Greenplum DISTRIBUTED BY + if (srctable->GetDistributionIsRandom()) + { + sql += wxT("\nDISTRIBUTED RANDOMLY"); + } + else if (srctable->GetDistributionColNumbers().Length() == 0) + { + // catalog table or other non-distributed table + } + else + { + // convert list of columns numbers to column names + wxStringTokenizer collist(srctable->GetDistributionColNumbers(), wxT(",")); + wxString cn; + wxString distributionColumns; + while (collist.HasMoreTokens()) + { + cn = collist.GetNextToken(); + pgSet *set = srctable->ExecuteSet( + wxT("SELECT attname\n") + wxT(" FROM pg_attribute\n") + wxT(" WHERE attrelid=") + srctable->GetOidStr() + wxT(" AND attnum IN (") + cn + wxT(")")); + if (set) + { + if (!distributionColumns.IsNull()) + { + distributionColumns += wxT(", "); + } + distributionColumns += qtIdent(set->GetVal(0)); + delete set; + } + } + + sql += wxT("\nDISTRIBUTED BY ("); + sql += distributionColumns; + + sql += wxT(")"); + } + + if (srctable->GetIsPartitioned()) + if (srctable->GetConnection()->BackendMinimumVersion(8, 2, 9) && srctable->GetConnection()->GetIsGreenplum()) + if (srctable->GetPartitionDef().Length() == 0) + { + wxString query = wxT("SELECT pg_get_partition_def("); + query += srctable->GetOidStr(); + query += wxT(", true) "); + wxString partition_def = srctable->GetDatabase()->ExecuteScalar(query); + srctable->iSetPartitionDef(partition_def); + // pg_get_partition_def() doesn't work on partitions + if (srctable->GetPartitionDef().Length() == 0) + srctable->iSetPartitionDef(wxT("-- This partition has subpartitions")); + } + if (srctable->GetPartitionDef().Length() > 0) + sql += wxT("\n") + srctable->GetPartitionDef() + wxT("\n"); + } + + + sql += wxT(";\n") + + srctable->GetOwnerSql(7, 3, wxT("TABLE ") + qtfullident); + + if (srctable->GetConnection()->BackendMinimumVersion(8, 2)) + sql += srctable->GetGrant(wxT("arwdxt"), wxT("TABLE ") + qtfullident); + else + sql += srctable->GetGrant(wxT("arwdRxt"), wxT("TABLE ") + qtfullident); + + wxString comment = srctable->GetCommentSql(); + comment.Replace(qtfullidentsrc, qtfullident); + sql += comment; + + // Column/constraint comments + if (!colDetails.IsEmpty()) + sql += colDetails + wxT("\n"); + + if (!conDetails.IsEmpty()) + sql += conDetails + wxT("\n"); + + if (!columnPrivileges.IsEmpty()) { + sql += columnPrivileges + wxT("\n"); + } + + return sqlcreate + sqlsequence + sql; + } + + pgTableCopyPaste::~pgTableCopyPaste() + { + } + + pgSequenceCopyPaste::pgSequenceCopyPaste(pgSequence *srcseq, pgSchema *targetschema, const wxString ©suffix1) + { + this->srcseq = srcseq; + this->targetschema = targetschema; + this->copysuffix = copysuffix1; + } + + wxString pgSequenceCopyPaste::GetSql(ctlTree *browser) + { + wxString sql = wxEmptyString; + wxString qtfullident; + wxString newtablename; + bool addsuffix = (!copysuffix.IsEmpty()); + if (addsuffix) + { + newtablename = srcseq->GetIdentifier() + copysuffix; + qtfullident = targetschema->GetQuotedPrefix() + qtIdent(newtablename); + } + else + qtfullident = targetschema->GetQuotedPrefix() + srcseq->GetQuotedIdentifier();; + wxString qtfullidentsrc = srcseq->GetQuotedFullIdentifier(); + + srcseq->UpdateValues(); + sql = wxT("-- Sequence: ") + qtfullident + wxT("\n\n") + + wxT("-- DROP SEQUENCE ") + qtfullident + wxT(";") + + wxT("\n\nCREATE SEQUENCE ") + qtfullident + + wxT("\n INCREMENT ") + srcseq->GetIncrement().ToString() + + wxT("\n MINVALUE ") + srcseq->GetMinValue().ToString() + + wxT("\n MAXVALUE ") + srcseq->GetMaxValue().ToString() + + wxT("\n START ") + srcseq->GetLastValue().ToString() + + wxT("\n CACHE ") + srcseq->GetCacheValue().ToString(); + if (srcseq->GetCycled()) + sql += wxT("\n CYCLE"); + sql += wxT(";\n") + + srcseq->GetOwnerSql(7, 3, wxT("TABLE ") + qtfullident); + + if (!srcseq->GetConnection()->BackendMinimumVersion(8, 2)) + sql += srcseq->GetGrant(wxT("arwdRxt"), wxT("TABLE ") + qtfullident); + else + sql += srcseq->GetGrant(wxT("rwU"), wxT("TABLE ") + qtfullident); + + wxString comment = srcseq->GetCommentSql(); + comment.Replace(qtfullidentsrc, qtfullident); + sql += comment; + + return sql; + } + + pgSequenceCopyPaste::~pgSequenceCopyPaste() + { + } + + copyTableFactory::copyTableFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list) + { + mnu->Append(id, _("&Copy table(s)..."), _("Store table(s) reference for later paste")); + } + + + wxWindow *copyTableFactory::StartDialog(frmMain *form, pgObject *obj) + { + if (!pasteTables::isActive()) + { + frmCopyTables::selectedTables.empty(); + if (copytObject) + { + delete copytObject; + copytObject = NULL; + } + pgObject *copyobj = obj; + pgSchema *schema = NULL; + pgTable *table = NULL; + if (copyobj) + { + pgDatabase *db = copyobj->GetDatabase(); + if (db) + { + if (db->GetConnected()) + { + table = dynamic_cast(copyobj); + if (table == 0) + { + schema = dynamic_cast(copyobj); + if (schema == 0) + { + copyobj = NULL; + } + } + } + else + copyobj = NULL; + } + else + copyobj = NULL; + } + if (copyobj) + { + copytObject = new copy_object_tag; + copytObject->groupname = copyobj->GetServer()->GetGroup(); + copytObject->servername = copyobj->GetServer()->GetName(); + copytObject->dbname = copyobj->GetDatabase()->GetName(); + copytObject->schemaname = (schema) ? schema->GetName() : wxT(""); + if (table) + { + copytObject->tablename = table->GetName(); + copytObject->schemaname = table->GetSchema()->GetName(); + } + else + copytObject->tablename = wxT(""); + copytObject->object = obj; + form->GetMenuFactories()->CheckMenu(obj, form->GetMenuBar(), (ctlMenuToolbar *)form->GetToolBar()); + } + } + return 0; + } + + + bool copyTableFactory::CheckEnable(pgObject *obj) + { + if (!obj || pasteTables::isActive()) + return false; + + if (obj->GetConnection()) + { + //tree item 'Tables' has GetMetaType() == PGM_TABLE ! + pgTable *table = (obj->GetMetaType() == PGM_TABLE) ? dynamic_cast(obj) : 0; + if (table) + return true; + //tree item 'Schemas' has GetMetaType() == PGM_SCHEMA ! + pgSchema *schema = (obj->GetMetaType() == PGM_SCHEMA) ? dynamic_cast(obj) : 0; + if (schema) + return true; + } + return false; + } + + + pasteTablesFactory::pasteTablesFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list) + { + mnu->Append(id, _("&Paste table(s)..."), _("Paste table(s)")); + this->toolbar = toolbar; + toolbar->AddTool(id, _("Paste table(s)"), *pastetables_png_bmp, _("Paste table(s) into schema."), wxITEM_NORMAL); + } + + + wxWindow *pasteTablesFactory::StartDialog(frmMain *form, pgObject *obj) + { + struct copy_object_tag *copyobj = copyTableFactory::copytObject; + pgDatabase *targetdatabase = ((pgSchema *)obj)->GetDatabase(); + if (copyobj) + { + pgDatabase *db = pasteTables::findDB(form, copyobj->groupname, copyobj->servername, copyobj->dbname); + if (db) + { + if (db->GetConnected()) + { + pgSchema *schema = pasteTables::findSchema(form, db, copyobj->schemaname); + if (schema && !copyobj->tablename.IsEmpty()) + { + pgTable *table = pasteTables::findTable(form, schema, copyobj->tablename); + if (table == 0) + { + copyobj = NULL; + } + } + } + else + copyobj = NULL; + } + else + copyobj = NULL; + } + if ((copyobj || !frmCopyTables::selectedTables.empty()) && !pasteTables::isActive()) + { + pasteTables::setActive(true); + pasteTables *copypasteobject = new pasteTables(winMain, copyobj, obj, this); + int numtables; + if (copyobj) + numtables = copypasteobject->process(); + else + numtables = copypasteobject->processListOfTables(); + if (numtables == 0) + { + delete copypasteobject; + winMain->SetCopypasteobject(NULL); + pasteTables::setActive(false); + } + else + { + form->SetCopypasteobject(copypasteobject); + } + form->GetMenuFactories()->CheckMenu((pgSchema *)obj, form->GetMenuBar(), (ctlMenuToolbar *)form->GetToolBar()); + } + return 0; + } + + + bool pasteTablesFactory::CheckEnable(pgObject *obj) + { + if (!obj) + return false; + + if (obj->GetConnection() && (copyTableFactory::copytObject) || !frmCopyTables::selectedTables.IsEmpty()) + { + //tree item 'Schemas' has GetMetaType() == PGM_SCHEMA ! + pgSchema *schema = (obj->GetMetaType() == PGM_SCHEMA) ? dynamic_cast(obj) : 0; + if (schema) + return true; + } + return false; + } + + copyTablesListFactory::copyTablesListFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list) + { + mnu->Append(id, _("&Copy tables from the list..."), _("Store tables reference for later paste")); + } + + + wxWindow *copyTablesListFactory::StartDialog(frmMain *form, pgObject *obj) + { + if (!pasteTables::isActive()) + { + frmCopyTables *frm = new frmCopyTables(form, obj); + form->GetMenuFactories()->CheckMenu(obj, form->GetMenuBar(), (ctlMenuToolbar *)form->GetToolBar()); + } + return 0; + } + + + bool copyTablesListFactory::CheckEnable(pgObject *obj) + { + if (pasteTables::isActive()) + return false; + if (!obj) + return false; + return obj->CanBackup(); + } + + #define ctvTablesCopy CTRL_CHECKTREEVIEW("ctvTablesCopy") + + BEGIN_EVENT_TABLE(frmCopyTables, ExecutionDialog) + EVT_BUTTON(wxID_OK, frmCopyTables::OnOK) + EVT_CLOSE( ExecutionDialog::OnClose) + END_EVENT_TABLE() + + frmCopyTables::frmCopyTables(frmMain *form, pgObject *_object) : ExecutionDialog(form, _object) + { + object = _object; + wxWindowBase::SetFont(settings->GetSystemFont()); + LoadResource(form, wxT("frmCopyTables")); + ctvTablesCopy->SetFont(settings->GetSystemFont()); + ctvTablesCopy->SetCopytables(this); + RestorePosition(); + SetIcon(*pastetables_png_ico); + + ctlTree *browser = form->GetBrowser(); + if (browser->ItemHasChildren(browser->GetRootItem())) + { + wxTreeItemId rootnode, groupnode, servernode, dbnode; + rootnode = ctvTablesCopy->AddRoot(_("Server Groups"), 2); + wxTreeItemIdValue groupcookie; + wxTreeItemId groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie); + while (groupitem) + { + groupnode = ctvTablesCopy->AppendItem(rootnode, browser->GetItemText(groupitem), 2); + wxCookieType cookie; + wxTreeItemId serverItem = browser->GetFirstChild(groupitem, cookie); + while (serverItem) + { + pgServer *server = (pgServer *)browser->GetObject(serverItem); + if (server && server->IsCreatedBy(serverFactory)) + { + hashgroupname[server->GetFullName()] = server->GetGroup(); + hashservername[server->GetFullName()] = server->GetDescription(); + hashservernamename[server->GetFullName()] = server->GetName(); + servernode = ctvTablesCopy->AppendItem(groupnode, server->GetFullName(), 2); + if (server->connection() && server->connection()->IsAlive()) + { + addDatabases(server, browser, servernode); + } + } + serverItem = browser->GetNextChild(groupitem, cookie); + } + groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie); + } + ctvTablesCopy->Expand(rootnode); + } + + Show(true); + } + + void frmCopyTables::OnOK(wxCommandEvent &ev) + { + copyTableFactory::copytObject = NULL; + frmCopyTables::selectedTables.empty(); + SavePosition(); + wxTreeItemId groupnode; + wxTreeItemIdValue groupcookie; + wxTreeItemIdValue childData; + wxTreeItemId rootnode = ctvTablesCopy->GetRootItem(); + wxTreeItemId childserver; + struct copy_object_tag *selection; + wxString groupname, servername, dbname, schemaname, tablename; + groupnode = ctvTablesCopy->GetFirstChild(rootnode, groupcookie); + while (groupnode) + { + groupname = ctvTablesCopy->GetItemText(groupnode); + int subseq = groupname.rfind(wxT("(")); + if (subseq != wxNOT_FOUND) + groupname = groupname.Mid(0, subseq); + childserver = ctvTablesCopy->GetFirstChild(groupnode, childData); + while (childserver) + { + servername = ctvTablesCopy->GetItemText(childserver); + wxTreeItemIdValue childData1; + wxTreeItemId childdb = ctvTablesCopy->GetFirstChild(childserver, childData1); + while (childdb) + { + dbname = ctvTablesCopy->GetItemText(childdb); + wxTreeItemIdValue childData2; + wxTreeItemId childschema = ctvTablesCopy->GetFirstChild(childdb, childData2); + while (childschema) + { + schemaname = ctvTablesCopy->GetItemText(childschema); + wxTreeItemIdValue childData3; + wxTreeItemId childtable = ctvTablesCopy->GetFirstChild(childschema, childData3); + while (childtable) + { + if (ctvTablesCopy->GetItemImage(childtable) == 1) + { + tablename = ctvTablesCopy->GetItemText(childtable); + selection = new struct copy_object_tag; + selection->groupname = hashgroupname[servername]; + selection->servername = hashservernamename[servername]; + selection->dbname = dbname; + selection->schemaname = schemaname; + selection->tablename = tablename; + selectedTables.Add(selection); + } + childtable = ctvTablesCopy->GetNextChild(childschema, childData3); + } + childschema = ctvTablesCopy->GetNextChild(childdb, childData2); + } + childdb = ctvTablesCopy->GetNextChild(childserver, childData1); + } + childserver = ctvTablesCopy->GetNextChild(groupnode, childData); + } + groupnode = ctvTablesCopy->GetNextChild(rootnode, groupcookie); + } + Destroy(); + mainForm->GetMenuFactories()->CheckMenu(object, mainForm->GetMenuBar(), (ctlMenuToolbar *)mainForm->GetToolBar()); + } + + wxString frmCopyTables::GetHelpPage() const + { + return wxEmptyString; + } + + wxString frmCopyTables::GetSql() + { + return wxEmptyString; + } + + frmCopyTables::~frmCopyTables() + { + SavePosition(); + ctvTablesCopy->SetCopytables(NULL); + } + + bool frmCopyTables::treeDetails(const wxString &fullservername, const wxString &dbname, const wxString &schemaname) + { + wxString groupname = hashgroupname[fullservername]; + wxString servername = hashservername[fullservername]; + wxString servernamename = hashservernamename[fullservername]; + pgDatabase *db; + pgSchema *srcschema; + pgTable *table; + wxTreeItemId childserver, childdb, childschema; + + pgServer *server = pasteTables::findServer(mainForm, groupname, servername); + if (!server) + return false; + if (!server->connection()) + { + server = mainForm->ConnectToServer(servername, true); + if (!server) + return false; + } + if (dbname.IsEmpty()) + { + wxTreeItemIdValue groupcookie; + wxTreeItemId groupitem; + wxTreeItemIdValue childData1; + groupitem = ctvTablesCopy->GetFirstChild(ctvTablesCopy->GetRootItem(), groupcookie); + while (groupitem) + { + wxTreeItemId servernode = ctvTablesCopy->GetFirstChild(groupitem, childData1); + wxString n1 = ctvTablesCopy->GetItemText(servernode); + while (servernode) + { + if (ctvTablesCopy->GetItemText(servernode) == server->GetFullName() && groupname == server->GetGroup()) + { + ctvTablesCopy->DeleteChildren(servernode); + addDatabases(server, mainForm->GetBrowser(), servernode); + return true; + } + servernode = ctvTablesCopy->GetNextChild(groupitem, childData1); + } + groupitem = ctvTablesCopy->GetNextChild(ctvTablesCopy->GetRootItem(), groupcookie); + } + return false; + } + + db = pasteTables::findDB(mainForm, groupname, servernamename, dbname); + if (db) + { + pgConn *conn = db->GetConnection(); + if (!conn || (conn && (!(!conn->IsAlive() && (conn->GetStatus() == PGCONN_BROKEN || conn->GetStatus() == PGCONN_BAD))))) + { + db->ShowTreeDetail(mainForm->GetBrowser()); + wxTreeItemIdValue groupcookie, childData; + wxTreeItemId rootnode = ctvTablesCopy->GetRootItem(); + wxTreeItemId groupitem = ctvTablesCopy->GetFirstChild(rootnode, groupcookie); + while (groupitem) + { + childserver = ctvTablesCopy->GetFirstChild(groupitem, childData); + while (childserver) + { + wxString txt = ctvTablesCopy->GetItemText(childserver); + if (txt == fullservername) + { + wxTreeItemIdValue childData1; + childdb = ctvTablesCopy->GetFirstChild(childserver, childData1); + while (childdb) + { + txt = ctvTablesCopy->GetItemText(childdb); + if (txt == db->GetName()) + { + if (schemaname.IsEmpty()) + { + ctvTablesCopy->DeleteChildren(childdb); + addSchemaTables(db, mainForm->GetBrowser(), childdb); + return true; + } + else + { + wxTreeItemIdValue childData2; + childschema = ctvTablesCopy->GetFirstChild(childdb, childData2); + while (childschema) + { + txt = ctvTablesCopy->GetItemText(childschema); + if (txt == schemaname) + { + ctvTablesCopy->DeleteChildren(childschema); + pgSchema *srcschema = pasteTables::findSchema(mainForm, db, schemaname); + if (srcschema) + { + srcschema->ShowTreeDetail(mainForm->GetBrowser()); + addTables(srcschema, mainForm->GetBrowser(), childschema); + return true; + } + } + childschema = ctvTablesCopy->GetNextChild(childdb, childData2); + } + } + } + childdb = ctvTablesCopy->GetNextChild(childserver, childData1); + } + } + childserver = ctvTablesCopy->GetNextChild(groupitem, childData); + } + groupitem = ctvTablesCopy->GetNextChild(rootnode, groupcookie); + } + return true; + } + } + + return false; + } + + void frmCopyTables::addDatabases(pgServer *server, ctlTree *browser, wxTreeItemId &servernode) + { + pgCollection *databases = browser->FindCollection(databaseFactory, server->GetId()); + if (databases) + { + pgObject *obj; + pgDatabase *srcdb; + treeObjectIterator dbIt(browser, databases); + while ((obj = dbIt.GetNextObject()) != 0) { + srcdb = (pgDatabase *)obj; + wxTreeItemId dbnode = ctvTablesCopy->AppendItem(servernode, srcdb->GetName(), 0); + // ctvTablesCopy->SetItemTextColour(dbnode, wxColour(102, 0, 51)); + addSchemaTables(srcdb, browser, dbnode); + } + } + } + + void frmCopyTables::addSchemaTables(pgDatabase *db, ctlTree *browser, wxTreeItemId &dbnode) + { + pgCollection *schemas = browser->FindCollection(schemaFactory, db->GetId()); + if (schemas) + { + pgObject *obj; + pgSchema *srcschema; + treeObjectIterator schIt(browser, schemas); + while ((obj = schIt.GetNextObject()) != 0) { + srcschema = (pgSchema *)obj; + wxTreeItemId schemanode = ctvTablesCopy->AppendItem(dbnode, srcschema->GetName(), 0); + // ctvTablesCopy->SetItemTextColour(schemanode, wxColour(0, 0, 0xFF)); + addTables(srcschema, browser, schemanode); + } + } + } + + void frmCopyTables::addTables(pgSchema *srcschema, ctlTree *browser, wxTreeItemId &schemanode) + { + pgCollection *tables = browser->FindCollection(tableFactory, srcschema->GetId()); + if (tables) + { + pgObject *obj; + pgTable *srctable; + treeObjectIterator tabIt(browser, tables); + while ((obj = tabIt.GetNextObject()) != 0) { + srctable = (pgTable *)obj; + wxTreeItemId tablenode = ctvTablesCopy->AppendItem(schemanode, srctable->GetName(), 0); + // ctvTablesCopy->SetItemTextColour(tablenode, wxColour(26, 94, 31)); + } + } + } *** a/pgadmin/include/ctl/ctlCheckTreeView.h --- b/pgadmin/include/ctl/ctlCheckTreeView.h *************** *** 24,35 **** class ctlCheckTreeView : public wxTreeCtrl --- 24,46 ---- public: ctlCheckTreeView(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxTR_HAS_BUTTONS); bool IsChecked(const wxTreeItemId &node); + void SetCopytables(void *copytables) + { + this->copytables = copytables; + } + + void *GetCopytables() const + { + return copytables; + } private: void OnLeftClick(wxMouseEvent &evt); void SetParentAndChildImage(wxTreeItemId node, int newimage); void SetParentImage(wxTreeItemId node, int newimage); + void *copytables; + DECLARE_EVENT_TABLE() }; *** a/pgadmin/include/db/pgConn.h --- b/pgadmin/include/db/pgConn.h *************** *** 124,129 **** public: --- 124,130 ---- void Close(); bool Reconnect(); bool ExecuteVoid(const wxString &sql, bool reportError = true); + PGresult * ExecuteOptionalResult(const wxString &sql, bool reportError = true); wxString ExecuteScalar(const wxString &sql); pgSet *ExecuteSet(const wxString &sql); wxString GetHostAddr() const *** a/pgadmin/include/frm/frmMain.h --- b/pgadmin/include/frm/frmMain.h *************** *** 24,29 **** --- 24,30 ---- #include "frm/frmQuery.h" #include "dlg/dlgClasses.h" #include "utils/factory.h" + #include "frm/pasteTables.h" // // This number MUST be incremented if changing any of the default perspectives *************** *** 82,87 **** enum --- 83,93 ---- REFRESH_OBJECT_AND_CHILDREN }; + // custom event declarations + BEGIN_DECLARE_EVENT_TYPES() + DECLARE_EVENT_TYPE(EVT_THREAD_COPYPASTE_UPDATE_GUI, -1) + END_DECLARE_EVENT_TYPES() + // Class declarations class frmMain : public pgFrame { *************** *** 162,167 **** public: --- 168,181 ---- void SetItemBackgroundColour(wxTreeItemId item, wxColour colour); wxString GetNodePath(wxTreeItemId node); + void SetCopypasteobject(pasteTables* copypasteobject) { + this->copypasteobject = copypasteobject; + } + pasteTables* GetCopypasteobject() const { + return copypasteobject; + } + + private: wxAuiManager manager; ctlTree *browser; *************** *** 184,189 **** private: --- 198,208 ---- actionFactory *scriptingMenuFactory; actionFactory *viewdataMenuFactory; + pasteTables *copypasteobject; + pgObject *m_draggedObject; + pasteTablesFactory *pastetablesfactory; + copyTableFactory *copytablefactory; + wxStopWatch stopwatch; wxString timermsg; long msgLevel; *************** *** 250,255 **** private: --- 269,278 ---- void CreatePluginUtility(PluginUtility *util); void ClearPluginUtility(PluginUtility *util); + void OnThreadCopypasteUpdateGUI(wxCommandEvent &event); + void OnBeginDrag(wxTreeEvent &event); + void OnEndDrag(wxTreeEvent &event); + DECLARE_EVENT_TABLE() }; *** a/pgadmin/include/frm/module.mk --- b/pgadmin/include/frm/module.mk *************** *** 1,38 **** ! ####################################################################### ! # ! # pgAdmin III - PostgreSQL Tools ! # ! # Copyright (C) 2002 - 2011, The pgAdmin Development Team ! # This software is released under the PostgreSQL Licence ! # ! # module.mk - pgadmin/include/frm/ Makefile fragment ! # ! ####################################################################### ! ! pgadmin3_SOURCES += \ ! $(srcdir)/include/frm/frmAbout.h \ ! $(srcdir)/include/frm/frmBackup.h \ ! $(srcdir)/include/frm/frmBackupGlobals.h \ ! $(srcdir)/include/frm/frmBackupServer.h \ ! $(srcdir)/include/frm/frmConfig.h \ ! $(srcdir)/include/frm/frmEditGrid.h \ ! $(srcdir)/include/frm/frmExport.h \ ! $(srcdir)/include/frm/frmGrantWizard.h \ ! $(srcdir)/include/frm/frmHbaConfig.h \ ! $(srcdir)/include/frm/frmHint.h \ ! $(srcdir)/include/frm/frmMain.h \ ! $(srcdir)/include/frm/frmMainConfig.h \ ! $(srcdir)/include/frm/frmMaintenance.h \ ! $(srcdir)/include/frm/frmOptions.h \ ! $(srcdir)/include/frm/frmPassword.h \ ! $(srcdir)/include/frm/frmPgpassConfig.h \ ! $(srcdir)/include/frm/frmQuery.h \ ! $(srcdir)/include/frm/frmReport.h \ ! $(srcdir)/include/frm/frmRestore.h \ ! $(srcdir)/include/frm/frmSplash.h \ ! $(srcdir)/include/frm/frmStatus.h \ ! $(srcdir)/include/frm/menu.h ! ! EXTRA_DIST += \ ! $(srcdir)/include/frm/module.mk ! --- 1,40 ---- ! ####################################################################### ! # ! # pgAdmin III - PostgreSQL Tools ! # ! # Copyright (C) 2002 - 2011, The pgAdmin Development Team ! # This software is released under the PostgreSQL Licence ! # ! # module.mk - pgadmin/include/frm/ Makefile fragment ! # ! ####################################################################### ! ! pgadmin3_SOURCES += \ ! $(srcdir)/include/frm/frmAbout.h \ ! $(srcdir)/include/frm/frmBackup.h \ ! $(srcdir)/include/frm/frmBackupGlobals.h \ ! $(srcdir)/include/frm/frmBackupServer.h \ ! $(srcdir)/include/frm/frmConfig.h \ ! $(srcdir)/include/frm/frmEditGrid.h \ ! $(srcdir)/include/frm/frmExport.h \ ! $(srcdir)/include/frm/frmGrantWizard.h \ ! $(srcdir)/include/frm/frmHbaConfig.h \ ! $(srcdir)/include/frm/frmHint.h \ ! $(srcdir)/include/frm/frmMain.h \ ! $(srcdir)/include/frm/frmMainConfig.h \ ! $(srcdir)/include/frm/frmMaintenance.h \ ! $(srcdir)/include/frm/frmOptions.h \ ! $(srcdir)/include/frm/frmPassword.h \ ! $(srcdir)/include/frm/frmPgpassConfig.h \ ! $(srcdir)/include/frm/frmQuery.h \ ! $(srcdir)/include/frm/frmReport.h \ ! $(srcdir)/include/frm/frmRestore.h \ ! $(srcdir)/include/frm/frmSplash.h \ ! $(srcdir)/include/frm/frmStatus.h \ ! $(srcdir)/include/frm/menu.h \ ! $(srcdir)/include/frm/pasteTables.h ! ! ! EXTRA_DIST += \ ! $(srcdir)/include/frm/module.mk ! *** /dev/null --- b/pgadmin/include/frm/pasteTables.h *************** *** 0 **** --- 1,225 ---- + ////////////////////////////////////////////////////////////////////////// + // + // pgAdmin III - PostgreSQL Tools + // + // Copyright (C) 2002 - 2011, The pgAdmin Development Team + // This software is released under the PostgreSQL Licence + // + // pasteTables.h - Copy/Paste table(s) functions + // + ////////////////////////////////////////////////////////////////////////// + + #ifndef PASTETABLES_H + #define PASTETABLES_H + + #include + #include + + class pasteTables; + class copyTableFactory; + class pasteTablesFactory; + + #include "pgAdmin3.h" + #include "frm/frmMain.h" + #include "schema/pgObject.h" + #include "schema/pgSchema.h" + #include "schema/pgTable.h" + #include "schema/pgSequence.h" + #include "ctl/ctlCheckTreeView.h" + + // Icons + #include "images/pastetables.pngc" + + struct copy_object_tag + { + wxString groupname; + wxString servername; + wxString dbname; + wxString schemaname; + wxString tablename; + pgObject *object; + }; + + class pasteTables; + class pgTableCopyPaste; + class pgTableCopyPasteArray; + + struct transfer_tag + { + pasteTables *THIS; + pgDatabase *srcdatabase; + wxString srcschemaname; + pgSchema *srcschema; + pgDatabase *targetdatabase; + wxString targetschemaname; + pgSchema *targetschema; + pgTableCopyPaste *table; + wxString createsql; + wxString searchPath; + pgConn *sourceconn; + pgConn *targetconn; + int numberOfCopypasteTables; + bool pastesuccess; + }; + + class copyPasteThread : public wxThread + { + private: + struct transfer_tag *transfer; + public: + copyPasteThread(struct transfer_tag *transfer1) + : wxThread(wxTHREAD_JOINABLE), transfer(transfer1) + {} + virtual void *Entry(); + }; + + class pgTableCopyPaste + { + public: + pgTableCopyPaste(pgTable *srctable, pgSchema *targetschema, const wxString ©suffix, + pgCollection *columns1, pgCollection *constraints1, pgCollection *tables1, pgCollection *sequences1); + virtual ~pgTableCopyPaste(); + virtual wxString GetSql(ctlTree *browser); + pgTable *Getsrctable() { return srctable; } + pgSchema *Gettargetschema() { return targetschema; } + wxString copysuffix; + wxString srcgroupname; + wxString srcservername; + wxString srcdbname; + wxString srctablename; + wxString targetgroupname; + wxString targetservername; + wxString targetdbname; + private: + pgTable *srctable; + pgSchema *targetschema; + pgCollection *columns; + pgCollection *constraints; + pgCollection *tables; + pgCollection *sequences; + wxString GetSequenceName(const wxString &definition, bool schemaonly = false); + }; + + class pasteTablesFactory; + class pasteTables + { + public: + pasteTables(frmMain *form, struct copy_object_tag *sourceobj, pgObject *targetobj, pasteTablesFactory *factory); + int process(); + int processListOfTables(); + bool pasteNextTable(); + void commitChanges(); + virtual ~pasteTables(); + void copyTable(struct transfer_tag *transfer); + static pgTable *findTable(frmMain *form, pgSchema *srcschema, const wxString &tablename); + static pgSchema *findSchema(frmMain *form, pgDatabase *database, const wxString &schemaname); + static pgDatabase *findDB(frmMain *form, const wxString &groupname, const wxString &servername, const wxString &dbname, bool shouldbeconnected = true); + static pgServer *findServer(frmMain *form, const wxString &groupname, const wxString &servername); + frmMain *Getmainform() + { + return mainform; + } + pasteTablesFactory *GetFactory() + { + return factory; + } + static void setActive(bool active) + { + pasteTables::active = active; + } + static bool isActive() { + return pasteTables::active; + } + pgObject *getTargetobj() const { + return targetobj; + } + int copied; + pgTableCopyPasteArray *tableCopyPasteArray; + copyPasteThread *thread; + pgError lastResultError; + private: + bool tableExists(pgSchema *srcschema, wxString &tablename); + void GetLastResultError(pgConn *conn, PGresult *res, const wxString &msg = wxT("")); + void handleCopyOut(pgConn *conn, wxFile & copystream); + void handleCopyIn(pgConn *conn, wxFile & copystream, bool isbinary); + void do_copy(pgConn *conn, wxString & sql, wxFile & copystream); + void myLogNotice(const wxChar *szFormat, ...); + + frmMain *mainform; + struct copy_object_tag *sourceobj; + pgObject *targetobj; + wxString pastemsg; + struct transfer_tag *transfer; + pasteTablesFactory *factory; + static bool active; + }; + + class pgSequenceCopyPaste + { + public: + pgSequenceCopyPaste(pgSequence *srcseq, pgSchema *targetschema, const wxString ©suffix); + virtual ~pgSequenceCopyPaste(); + virtual wxString GetSql(ctlTree *browser); + private: + pgSequence *srcseq; + pgSchema *targetschema; + wxString copysuffix; + }; + + WX_DECLARE_OBJARRAY(pgTableCopyPaste, pgTableCopyPasteArray); + + WX_DECLARE_STRING_HASH_MAP(wxString, MyHash); + + WX_DECLARE_OBJARRAY(struct copy_object_tag, selectedTablesArray); + + class frmCopyTables : public ExecutionDialog + { + public: + frmCopyTables(frmMain *form, pgObject *_object); + ~frmCopyTables(); + wxString GetSql(); + bool treeDetails(const wxString &servername, const wxString &dbname, const wxString &schemaname); + MyHash hashgroupname, hashservername, hashservernamename; + static selectedTablesArray selectedTables; + private: + wxString GetHelpPage() const; + void OnOK(wxCommandEvent &ev); + void addDatabases(pgServer *server, ctlTree *browser, wxTreeItemId &servernode); + void addSchemaTables(pgDatabase *db, ctlTree *browser, wxTreeItemId &dbnode); + void addTables(pgSchema *srcschema, ctlTree *browser, wxTreeItemId &schemanode); + pgObject *object; + + DECLARE_EVENT_TABLE() + }; + + class copyTableFactory : public contextActionFactory + { + public: + copyTableFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar); + wxWindow *StartDialog(frmMain *form, pgObject *obj); + bool CheckEnable(pgObject *obj); + static struct copy_object_tag *copytObject; + }; + + class copyTablesListFactory : public contextActionFactory + { + public: + copyTablesListFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar); + wxWindow *StartDialog(frmMain *form, pgObject *obj); + bool CheckEnable(pgObject *obj); + }; + + class pasteTablesFactory : public contextActionFactory + { + public: + pasteTablesFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar); + wxWindow *StartDialog(frmMain *form, pgObject *obj); + bool CheckEnable(pgObject *obj); + ctlMenuToolbar *GetToolbar() + { + return toolbar; + } + private: + ctlMenuToolbar *toolbar; + }; + #endif /* PASTETABLES_H */ *** a/pgadmin/include/images/module.mk --- b/pgadmin/include/images/module.mk *************** *** 291,297 **** pgadmin3_SOURCES += \ $(srcdir)/include/images/ex_gather_motion.png \ $(srcdir)/include/images/exttable-sm.png \ $(srcdir)/include/images/exttables.png \ ! $(srcdir)/include/images/exttable.png EXTRA_DIST += \ $(srcdir)/include/images/module.mk \ --- 291,298 ---- $(srcdir)/include/images/ex_gather_motion.png \ $(srcdir)/include/images/exttable-sm.png \ $(srcdir)/include/images/exttables.png \ ! $(srcdir)/include/images/exttable.png \ ! $(srcdir)/include/images/pastetables.png EXTRA_DIST += \ $(srcdir)/include/images/module.mk \ *** a/pgadmin/include/schema/pgTable.h --- b/pgadmin/include/schema/pgTable.h *************** *** 117,122 **** public: --- 117,126 ---- distributionColNumbers = s; // for Greenplum if (s.Length() > 0) distributionIsRandom = false; } + bool GetDistributionIsRandom() const + { + return distributionIsRandom; // for Greenplum + } void iSetDistributionIsRandom() { distributionIsRandom = true; *** a/pgadmin/schema/pgColumn.cpp --- b/pgadmin/schema/pgColumn.cpp *************** *** 301,306 **** wxString pgColumn::GetDefinition() --- 301,307 ---- { wxString sql = wxEmptyString; wxString seqDefault1, seqDefault2; + bool sequence9 = (GetDatabase()->BackendMinimumVersion(9, 0)); if (table->GetOfTypeOid() == 0) sql += GetQuotedTypename(); *************** *** 327,333 **** wxString pgColumn::GetDefinition() if ((sql == wxT("integer") || sql == wxT("bigint") || sql == wxT("pg_catalog.integer") || sql == wxT("pg_catalog.bigint")) ! && (GetDefault() == seqDefault1 || GetDefault() == seqDefault2)) { if (sql.Right(6) == wxT("bigint")) sql = wxT("bigserial"); --- 328,335 ---- if ((sql == wxT("integer") || sql == wxT("bigint") || sql == wxT("pg_catalog.integer") || sql == wxT("pg_catalog.bigint")) ! && ((sequence9 && !GetSerialSequence().IsEmpty()) || ! (!sequence9 && (GetDefault() == seqDefault1 || GetDefault() == seqDefault2)))) { if (sql.Right(6) == wxT("bigint")) sql = wxT("bigserial"); *** /dev/null --- b/pgadmin/ui/frmCopyTables.xrc *************** *** 0 **** --- 1,53 ---- + + + + Copy tables selection + 800,600d + + + 1 + 2 + 0 + 0 + + + + + wxEXPAND|wxALL + 3 + + + + 4 + 1 + + + + + wxEXPAND|wxALL + 3 + + + 0,0d + + + + + 1 + + wxEXPAND|wxALL + 3 + + + + + + wxEXPAND|wxALL + 3 + + + wxEXPAND|wxTOP|wxLEFT|wxRIGHT + + + + *** a/pgadmin/ui/module.mk --- b/pgadmin/ui/module.mk *************** *** 90,96 **** TMP_ui += \ $(srcdir)/ui/frmOptions.xrc \ $(srcdir)/ui/frmPassword.xrc \ $(srcdir)/ui/frmReport.xrc \ ! $(srcdir)/ui/frmRestore.xrc EXTRA_DIST += \ $(srcdir)/ui/module.mk \ --- 90,97 ---- $(srcdir)/ui/frmOptions.xrc \ $(srcdir)/ui/frmPassword.xrc \ $(srcdir)/ui/frmReport.xrc \ ! $(srcdir)/ui/frmRestore.xrc \ ! $(srcdir)/ui/frmCopyTables.xrc EXTRA_DIST += \ $(srcdir)/ui/module.mk \