Hi, Finally I've made Copy/Paste table(s) operations !
Usage is very simple and intuitive: on right mouse menu for selected connected table or schema select 'Copy table(s)' and than on other connected schema on right mouse menu select 'Paste table(s). Source target server-db might be different but always connected. Best regards, Vladimir Kokovic, DP senior, Belgrade, Serbia
frmMain-h.diff
Description: Binary data
frmMain-cpp.diff
Description: Binary data
//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2011, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// frmPasteObject.h - Copy/Paste table(s) functions
//
//////////////////////////////////////////////////////////////////////////
#ifndef FRMPASTEOBJECT_H
#define FRMPASTEOBJECT_H
#include "frm/frmMain.h"
#include "schema/pgObject.h"
class frmPasteObject
{
public:
frmPasteObject(frmMain *form, pgObject *sourceobj, pgObject *targetobj);
void process();
virtual ~frmPasteObject();
private:
frmMain *mainform;
pgObject *sourceobj;
pgObject *targetobj;
};
#endif /* FRMPASTEOBJECT_H */
//////////////////////////////////////////////////////////////////////////
//
// 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 <wx/wx.h>
#include <wx/wfstream.h>
// PostgreSQL headers
#include <libpq-fe.h>
#include "pgAdmin3.h"
#include "frm/frmPasteObject.h"
#include "schema/pgSchema.h"
#include "schema/pgTable.h"
#include "schema/pgColumn.h"
#include "schema/pgSequence.h"
#include "schema/pgConstraints.h"
#include "utils/misc.h"
#include "schema/pgForeignKey.h"
#include "schema/pgIndexConstraint.h"
#include "schema/pgCheck.h"
#include <errno.h>
frmPasteObject::frmPasteObject(frmMain *form, pgObject *sourceobj, pgObject *targetobj)
{
this->mainform = form;
this->sourceobj= sourceobj;
this->targetobj= targetobj;
}
wxArrayString *getSchemaTables(pgSchema *srcschema)
{
wxArrayString *objArray = new wxArrayString();
wxString query = wxT("SELECT relname ")
wxT("FROM pg_namespace n ")
wxT("LEFT JOIN pg_class c ON n.oid=c.relnamespace AND relkind='r' ")
wxT("WHERE nspname='") + srcschema->GetIdentifier() + wxT("'");
query += wxT("ORDER BY relname");
pgSet *objects = srcschema->GetDatabase()->ExecuteSet(query);
if (objects)
{
while (!objects->Eof())
{
if (!objects->GetVal(wxT("relname")).IsNull())
{
objArray->Add(objects->GetVal(wxT("relname")));
}
objects->MoveNext();
}
delete objects;
}
return objArray;
}
/*
* 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.
*/
wxString
handleCopyOut(PGconn *conn, wxFile & copystream)
{
bool OK = true;
char *buf;
int ret;
PGresult *res;
wxString lastError;
for (;;)
{
ret = PQgetCopyData(conn, &buf, 0);
if (ret < 0)
break; /* done or error */
if (buf)
{
if (copystream.Write(wxString(buf, wxConvUTF8)) != ret)
{
if (OK) /* complain only once, keep reading data */
lastError.Format(_("could not write COPY data: %s\n"), strerror(errno));
OK = false;
}
PQfreemem(buf);
}
}
if (OK && copystream.Flush())
{
lastError.Format(_("could not write COPY data: %s\n"), strerror(errno));
OK = false;
}
if (ret == -2)
{
lastError.Format(_("COPY data transfer failed: %s"), PQerrorMessage(conn));
OK = false;
}
/* Check command status and return to normal libpq state */
res = PQgetResult(conn);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
lastError.Format(wxT("%s"), PQerrorMessage(conn));
OK = false;
}
PQclear(res);
return lastError;
}
/*
* 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
wxString
handleCopyIn(PGconn *conn, wxFile & copystream, bool isbinary)
{
bool OK;
char buf[COPYBUFSIZ];
PGresult *res;
wxString lastError;
int counter = 0;
OK = true;
if (isbinary)
{
for (;;)
{
int buflen;;
buflen = copystream.Read(buf, 1);
if (buflen <= 0)
break;
if (PQputCopyData(conn, buf, buflen) <= 0)
{
OK = false;
break;
}
}
}
else
{
wxFileInputStream input(copystream);
wxTextInputStream textfile(input);
while (input.CanRead()) /* for each bufferload in line ... */
{
counter++;
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, tmp, lenc) <= 0)
{
OK = false;
break;
}
}
}
/* Terminate data transfer */
const char *errmsg = "aborted because of read failure";
if (PQputCopyEnd(conn, OK ? NULL : errmsg) <= 0)
OK = false;
/* Check command status and return to normal libpq state */
res = PQgetResult(conn);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
lastError = wxString::FromAscii(PQerrorMessage(conn));
OK = false;
}
PQclear(res);
return lastError;
}
/*
* 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.
*/
wxString
do_copy(PGconn *conn, wxString & sql, wxFile & copystream)
{
PGresult *result;
struct stat st;
wxString lastError;
result = PQexec(conn, (const char *)sql.mb_str());
switch (PQresultStatus(result))
{
case PGRES_COPY_OUT:
lastError = ::handleCopyOut(conn, copystream);
break;
case PGRES_COPY_IN:
lastError = ::handleCopyIn(conn, copystream, PQbinaryTuples(result));
break;
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
lastError.Format(_("copy: %s"), PQerrorMessage(conn));
break;
default:
lastError.Format(_("copy: unexpected response (%d)\n"), PQresultStatus(result));
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)) != NULL)
{
lastError.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, (const char *)_("trying to exit copy mode"));
PQclear(result);
}
return lastError;
}
wxString copyTable(ctlTree *browser, pgSchema *srcschema, pgSchema *targetschema, pgTable *table1)
{
pgConn *sourceconn = srcschema->GetConnection();
pgConn *targetconn = targetschema->GetConnection();
bool rc;
wxString lastError;
rc = targetconn->ExecuteVoid(wxT("BEGIN"));
lastError = targetconn->GetLastError();
if (!rc) return lastError;
table1->ShowTreeDetail(browser);
pgCollection *columns = table1->GetColumnCollection(browser);
treeObjectIterator colIt(browser, columns);
pgColumn *column;
wxString colName, defval;
while ((column = (pgColumn *)colIt.GetNextObject()) != 0)
{
column->ShowTreeDetail(browser);
if (column->GetColNumber() > 0)
{
colName = column->GetName();
defval = column->GetDefault();
if (!defval.IsNull() && defval.StartsWith(wxT("nextval(")))
{
wxStringTokenizer parts(defval, wxT("'"));
int i = 0;
while (parts.HasMoreTokens())
{
wxString part = parts.GetNextToken();
if (i == 1)
{
wxString seqsch, seqname;
int subseq = part.Find('.');
if (subseq == wxNOT_FOUND)
{
seqsch = wxT("public");
seqname = part;
}
else
{
seqsch = part.Mid(0, subseq - 1);
seqname = part.Mid(subseq + 1);
}
wxLongLong lastValue, minValue, maxValue, cacheValue, increment;
bool cycled, called;
wxString owner, comment, acl;
pgSequence seq = pgSequence(srcschema, seqname);
pgSet *seqcat = srcschema->GetDatabase()->ExecuteSet(
wxT("SELECT pg_get_userbyid(relowner) AS seqowner, relacl, description\n")
wxT(" FROM pg_class cl\n")
wxT(" LEFT OUTER JOIN pg_description des ON des.objoid=cl.oid\n")
wxT(" WHERE relkind = 'S' AND relnamespace = ") + srcschema->GetOidStr() +
wxT(" AND relname = ") + seq.qtDbString(seqname) + wxT("\n"));
if (seqcat)
{
comment = seqcat->GetVal(wxT("description"));
owner = seqcat->GetVal(wxT("seqowner"));
acl = seqcat->GetVal(wxT("relacl"));
delete seqcat;
}
else
{
goto Error;
}
seq.iSetAcl(acl);
pgSet *sequence = srcschema->GetDatabase()->ExecuteSet(
wxT("SELECT last_value, min_value, max_value, cache_value, is_cycled, increment_by, is_called\n")
wxT(" FROM ") + seq.GetQuotedFullIdentifier());
if (sequence)
{
lastValue = sequence->GetLongLong(wxT("last_value"));
minValue = sequence->GetLongLong(wxT("min_value"));
maxValue = sequence->GetLongLong(wxT("max_value"));
cacheValue = sequence->GetLongLong(wxT("cache_value"));
increment = sequence->GetLongLong(wxT("increment_by"));
cycled = sequence->GetBool(wxT("is_cycled"));
called = sequence->GetBool(wxT("is_called"));
delete sequence;
}
else
{
goto Error;
}
pgSequence seqnew = pgSequence(targetschema, seqname);
wxString sql = wxT("-- Sequence: ") + seqnew.GetQuotedFullIdentifier() + wxT("\n\n")
+ wxT("-- DROP SEQUENCE ") + seqnew.GetQuotedFullIdentifier() + wxT(";")
+ wxT("\n\nCREATE SEQUENCE ") + seqnew.GetQuotedFullIdentifier()
+ wxT("\n INCREMENT ") + increment.ToString()
+ wxT("\n MINVALUE ") + minValue.ToString()
+ wxT("\n MAXVALUE ") + maxValue.ToString()
+ wxT("\n START ") + lastValue.ToString()
+ wxT("\n CACHE ") + cacheValue.ToString();
if (cycled)
sql += wxT("\n CYCLE");
sql += wxT(";\nALTER TABLE ")
+ seqnew.GetQuotedFullIdentifier() + wxT(" OWNER TO ") + qtIdent(owner) + wxT(";\n");
if (!seq.GetConnection()->BackendMinimumVersion(8, 2))
sql += seq.GetGrant(wxT("arwdRxt"), wxT("TABLE ") + seqnew.GetQuotedFullIdentifier());
else
sql += seq.GetGrant(wxT("rwU"), wxT("TABLE ") + seqnew.GetQuotedFullIdentifier());
wxString cmt;
if (!comment.IsNull())
{
cmt = wxT("COMMENT ON SEQUENCE ") + seqnew.GetQuotedFullIdentifier()
+ wxT(" IS ") + seqnew.qtDbString(comment) + wxT(";\n");
sql += cmt;
}
rc = targetconn->ExecuteVoid(sql, false);
if (!rc) goto Error;
break;
}
i++;
}
}
}
}
{
wxString createsql = table1->GetSql(browser);
createsql.Replace(srcschema->GetIdentifier() + wxT("."), targetschema->GetIdentifier() + wxT("."), true);
rc = targetconn->ExecuteVoid(createsql, false);
if (!rc) goto Error;
if (sourceconn->GetDbname() + sourceconn->GetHost() == targetconn->GetDbname() + targetconn->GetHost())
{
wxString copysql =
wxT("\nINSERT INTO ")
+ targetschema->GetQuotedPrefix() + table1->GetQuotedIdentifier()
+ wxT(" (SELECT * FROM ")
+ srcschema->GetQuotedPrefix() + table1->GetQuotedIdentifier()
+ wxT(")\n\n");
rc = targetconn->ExecuteVoid(copysql, false);
if (!rc) goto Error;
}
else
{
wxString tmpFilename;
wxFile tmpFile;
tmpFilename = wxFileName::CreateTempFileName(wxT("copyobject"));
tmpFile.Open(tmpFilename.c_str(), wxFile::write);
if (!tmpFile.IsOpened())
{
lastError = _("Can't create temporary file: ") + tmpFilename;
goto Error1;
}
wxString copysql =
wxT("COPY ")
+ srcschema->GetQuotedPrefix() + table1->GetQuotedIdentifier()
+ wxT(" TO STDOUT");
lastError = ::do_copy(sourceconn->connection(), copysql, tmpFile);
if (lastError == wxEmptyString)
{
tmpFile.Close();
tmpFile.Open(tmpFilename.c_str(), wxFile::read);
if (!tmpFile.IsOpened())
{
lastError = _("Can't open temporary file: ") + tmpFilename;
wxRemoveFile(tmpFilename);
goto Error1;
}
copysql =
wxT("COPY ")
+ targetschema->GetQuotedPrefix() + table1->GetQuotedIdentifier()
+ wxT(" FROM STDIN");
lastError = ::do_copy(targetconn->connection(), copysql, tmpFile);
}
tmpFile.Close();
wxRemoveFile(tmpFilename);
if (lastError != wxEmptyString)
{
goto Error1;
}
}
goto Success;
}
Error:
lastError = targetconn->GetLastError();
Error1:
targetconn->ExecuteVoid(wxT("ROLLBACK"));
return lastError;
Success:
targetconn->ExecuteVoid(wxT("COMMIT"));
return lastError;;
}
void frmPasteObject::process()
{
if (!sourceobj || !targetobj)
{
return;
}
wxArrayString *srcObjArray;
pgSchema *targetschema = (pgSchema *)targetobj;
pgSchema *srcschema = 0;
pgTable *table = (sourceobj->GetMetaType() == PGM_TABLE) ? (pgTable *)sourceobj : 0;
if (table)
{
wxMessageBox(
wxT("Paste source table\n") +
table->GetSchema()->GetDatabase()->GetIdentifier() + wxT(".") + table->GetSchema()->GetIdentifier() + wxT(".") + table->GetIdentifier() + wxT("\n") +
wxT(" into schema\n") + targetschema->GetDatabase()->GetIdentifier() + wxT(".") + targetschema->GetIdentifier());
}
else
{
srcschema = (pgSchema *)sourceobj;
wxMessageBox(
wxT("Paste source schema objects\n") +
srcschema->GetDatabase()->GetIdentifier() + wxT(".") + srcschema->GetIdentifier() + wxT("\n") +
wxT(" into schema\n") +
targetschema->GetDatabase()->GetIdentifier() + wxT(".") + targetschema->GetIdentifier());
}
pgConn *sourceconn = sourceobj->GetConnection();
pgConn *targetconn = targetobj->GetConnection();
if (!sourceconn || !targetconn)
{
wxMessageBox(
_("Both source and target schema connections should be established before paste object operation !"));
return;
}
if (srcschema)
{
srcObjArray = ::getSchemaTables(srcschema);
}
else
{
srcObjArray = new wxArrayString();
srcObjArray->Add(table->GetIdentifier());
srcschema = table->GetSchema();
}
if (srcschema->GetIdentifier() == targetschema->GetIdentifier())
{
wxMessageBox(_("Source and target schema should be different schema for paste object operation !"));
return;
}
srcschema->ShowTreeDetail(mainform->GetBrowser());
wxString msg;
for(unsigned int i = 0; i < srcObjArray->Count(); i++)
{
msg = _("COPY TABLE:") +
srcschema->GetDatabase()->GetIdentifier() + wxT(".") + srcschema->GetIdentifier() + wxT(".") + srcObjArray->Item(i) +
_(" INTO:") + targetschema->GetDatabase()->GetIdentifier() + wxT(".") + targetschema->GetIdentifier();
mainform->GetStatusBar()->SetStatusText(msg, 1);
//future implementation
pgTable *table1 = 0;
wxTreeItemIdValue schemacookie;
wxTreeItemId schemaid = srcschema->GetId();
wxTreeItemId schemaitem = mainform->GetBrowser()->GetFirstChild(schemaid, schemacookie);
bool found = false;
while (schemaitem && !found)
{
pgObject *obj = mainform->GetBrowser()->GetObject(schemaitem);
if (obj && obj->GetMetaType() == PGM_TABLE)
{
wxTreeItemIdValue tablecookie;
wxTreeItemId tableitem = mainform->GetBrowser()->GetFirstChild(obj->GetId(), tablecookie);
while (tableitem)
{
table1 = (pgTable *)mainform->GetBrowser()->GetObject(tableitem);
if (table1->GetIdentifier() == srcObjArray->Item(i))
{
found = true;
break;
}
table1 = 0;
tableitem = mainform->GetBrowser()->GetNextChild(obj->GetId(), tablecookie);
}
}
schemaitem = mainform->GetBrowser()->GetNextChild(schemaid, schemacookie);
}
if (!table1)
{
msg = _("WARNING SOURCE TABLE DISAPEARED:\n") +
srcschema->GetDatabase()->GetIdentifier() + wxT(".") + srcschema->GetIdentifier() + wxT(".") + srcObjArray->Item(i);
}
else
{
msg = ::copyTable(mainform->GetBrowser(), srcschema, targetschema, table1);
if (msg != wxEmptyString)
{
wxMessageBox(msg,
_("Cannot paste object:") +
targetschema->GetDatabase()->GetIdentifier() + wxT(".") + targetschema->GetIdentifier() + wxT(".") + table1->GetIdentifier(),
wxOK | wxICON_ERROR);
}
}
}
msg = wxString::Format(_("%d TABLE(s) COPIED FROM %s TO %s"), srcObjArray->Count(),
(srcschema->GetDatabase()->GetIdentifier() + wxT(".") + srcschema->GetIdentifier()).c_str(),
(targetschema->GetDatabase()->GetIdentifier() + wxT(".") + targetschema->GetIdentifier()).c_str());
mainform->GetStatusBar()->SetStatusText(msg, 1);
delete srcObjArray;
}
frmPasteObject::~frmPasteObject()
{
}
module-mk.diff
Description: Binary data
-- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers
