Hi,

Here's a new version of copy / paste table(s)!

I hope this is much better than the previous one..

Best regards,
Vladimir Kokovic, DP senior, Belgrade, Serbia

Attachment: frm-module.mk.diff
Description: Binary data

Attachment: frmMain.cpp.diff
Description: Binary data

Attachment: frmMain.h.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.cpp - Copy/Paste table(s) functions
//
//////////////////////////////////////////////////////////////////////////

// wxWindows headers
#include <wx/wfstream.h>

// PostgreSQL headers
#include <libpq-fe.h>

#include "frm/frmPasteObject.h"
#include "schema/pgColumn.h"
#include "schema/pgSequence.h"

#include <errno.h>

frmPasteObject::frmPasteObject(frmMain *form, pgObject *sourceobj, pgObject *targetobj)
{
	this->mainform = form;
	this->sourceobj= sourceobj;
	this->targetobj= targetobj;
}

wxArrayString frmPasteObject::getSchemaTables(pgSchema *srcschema)
{
	wxArrayString objArray;
	wxString srcname = srcschema->GetQuotedIdentifier();
	if (wxString(srcname[0]) == wxT("\""))
	{
		srcname = srcname.Mid(1, srcname.length() - 2);
		srcname.Replace(wxT("'"), wxT("''"), true);
	}

	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='") + srcname + 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;
}

bool frmPasteObject::tableExists(pgSchema *srcschema, wxString quotedtablename)
{
	wxString nspname = srcschema->GetQuotedIdentifier();
	if (wxString(nspname[0]) == wxT("\""))
	{
		nspname.Replace(wxT("'"), wxT("''"), true);
		nspname = nspname.Mid(1, nspname.length() - 2);
	}
	wxString relname = quotedtablename;
	if (wxString(relname[0]) == wxT("\""))
	{
		relname.Replace(wxT("'"), wxT("''"), true);
		relname = relname.Mid(1, relname.length() - 2);
	}
	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='") + nspname + wxT("' AND relname='") + relname + wxT("'");
	wxString result = srcschema->GetDatabase()->ExecuteScalar(query);
	return !result.IsEmpty();
}

void frmPasteObject::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 frmPasteObject::handleCopyOut(pgConn *conn, wxFile & copystream)
{
	bool		OK = true;
	char	   *buf;
	int			ret;
	PGresult   *res;

	lastResultError.formatted_msg = wxT("");
	for (;;)
	{
		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 frmPasteObject::handleCopyIn(pgConn *conn, wxFile & copystream, bool isbinary)
{
	bool		OK;
	char		buf[COPYBUFSIZ];
	PGresult    *res;
	int			counter = 0;

	OK = true;

	if (isbinary)
	{
		for (;;)
		{
			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++;
			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 frmPasteObject::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);
	}
}

wxArrayString frmPasteObject::stringToArray(wxString & src, wxString pattern)
{
	wxArrayString resArray;
	int pos, prevpos = 0;

	pos = src.find(pattern);
	while (pos != wxNOT_FOUND)
	{
		wxString subs = src.Mid(prevpos, pos - prevpos);
		if (!subs.IsEmpty())
		{
			resArray.Add(subs);
		}
		resArray.Add(pattern);
		prevpos = pos + pattern.length();
		pos = src.find(pattern, prevpos);
	}
	if (!resArray.IsEmpty()){
		wxString subs = src.Mid(prevpos);
		if (!subs.IsEmpty())
		{
			resArray.Add(subs);
		}
	}

	return resArray;
}

void frmPasteObject::copyTable(ctlTree *browser, pgSchema *srcschema, pgSchema *targetschema, pgTable *table1)
{
	lastResultError.formatted_msg = wxT("");

	pgConn *sourceconn = srcschema->GetConnection();
	pgConn *targetconn = targetschema->GetConnection();
	bool rc;

	rc = tableExists(targetschema, table1->GetQuotedIdentifier());
	if (rc)
	{
		lastResultError.formatted_msg = wxT("TABLE EXISTS");
		return;
	}

	rc = targetconn->ExecuteVoid(wxT("BEGIN"));
	if (!rc)
	{
		lastResultError = targetconn->GetLastResultError();
		lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
		return;
	}

	table1->ShowTreeDetail(browser);
	pgCollection *columns = table1->GetColumnCollection(browser);
	treeObjectIterator colIt(browser, columns);
	pgColumn *column;
	wxString colName, defval, serialname;
	while ((column = (pgColumn *)colIt.GetNextObject()) != 0)
	{
		column->ShowTreeDetail(browser);
		if (column->GetColNumber() > 0)
		{
			colName = column->GetName();
			serialname = column->GetSerialSequence();
			defval = column->GetDefault();
			//uniqueid integer DEFAULT nextval(('ps_nalog_uniqueid_seq'::text)::regclass),
			if (!defval.IsNull() && serialname.IsEmpty() && defval.StartsWith(wxT("nextval(")))
			{
				wxString oidstr;
				wxString seqsch, seqname;
				int pos = wxString(wxT("nextval(")).length();
				if (wxString(defval[pos]) == wxT("("))
				{
					pos++;
				}
				pos++;
				if (wxString(defval[pos]) == wxT("\""))
				{
					wxString newdefval = defval.Mid(pos + 1);
					newdefval.Replace(wxT("\"\""), wxT("  "), true);

					int subseq = newdefval.Find(wxT("\"."));
					if (subseq == wxNOT_FOUND)
					{
						lastResultError.formatted_msg = _("Can't find schema sequence delimiter:") + defval;
						return;
					}
					seqsch = defval.Mid(pos + 1, subseq);
					seqsch.Replace(wxT("\"\""), wxT("\""), true);
					seqsch = wxT("\"") + seqsch + wxT("\"");
					subseq += 2;
					int subseq1 = newdefval.Mid(subseq + 2).Find(wxT("'::text)"));
					if (subseq1 == wxNOT_FOUND)
					{
						subseq1 = newdefval.Mid(subseq + 2).Find(wxT("'::regclass)"));
						if (subseq1 == wxNOT_FOUND)
						{
							lastResultError.formatted_msg = _("Can't find sequence name:") + defval;
							return;
						}
					}
					seqname = defval.Mid(pos + subseq + 1, subseq1 + 2);
					if (wxString(seqname[0]) == wxT("\""))
					{
						seqname = seqname.Mid(1, seqname.length() - 2);
						seqname.Replace(wxT("\"\""), wxT("\""), true);
						seqname = wxT("\"") + seqname + wxT("\"");
					}
				}
				else
				{
					bool nextval = false;
					wxArrayString resarray = stringToArray(defval, wxT("nextval("));
					for(unsigned int j = 0; j < resarray.Count(); j++)
					{
						wxString part = resarray.Item(j);
						if (part == wxT("nextval("))
						{
							nextval = true;
							continue;
						}
						if (!nextval)
						{
							continue;
						}
						nextval = false;
						int subseq = part.Find('.');
						if (subseq == wxNOT_FOUND)
						{
							seqsch = wxT("public");
							seqname = part;
							if (seqname.StartsWith(wxT("(")))
							{
								seqname = seqname.Mid(1);
							}
							if (seqname.StartsWith(wxT("'")))
							{
								seqname = seqname.Mid(1);
							}
							int pos = seqname.find(wxT("'::text)"));
							if (pos == wxNOT_FOUND)
							{
								pos = seqname.find(wxT("'::regclass)"));
								if (pos == wxNOT_FOUND)
								{
									lastResultError.formatted_msg = _("Can't find sequence name delimiter::regclass)") + defval;
									return;
								}
							}
							seqname = seqname.Mid(0, pos);
						} else
						{
							if (part.StartsWith(wxT("(")))
							{
								part = part.Mid(1);
							}
							seqsch = part.Mid(1, subseq - 1);
							seqname = part.Mid(subseq + 1);
							int subseq = seqname.Find(wxT("'"));
							if (subseq == wxNOT_FOUND)
							{
								lastResultError.formatted_msg = _("Can't find sequence name delimiter:") + defval;
								return;
							}
							seqname = seqname.Mid(0, subseq);
						}
						break;
					}
				}
				if (seqsch == srcschema->GetIdentifier())
				{
					oidstr = srcschema->GetOidStr();
				}
				else
				{
					wxString seqsch1 = seqsch;
					if (wxString(seqsch[0]) == wxT("\""))
					{
						seqsch1 = seqsch.Mid(1, seqsch.length() - 2);
					}
					pgSet *seqcat = srcschema->GetDatabase()->ExecuteSet(
						wxT("SELECT oid\n")
						wxT(" FROM pg_namespace\n")
						wxT(" WHERE nspname = '") + seqsch1 + wxT("'\n"));
					if (seqcat)
					{
						OID nspoid = seqcat->GetOid(wxT("oid"));
						oidstr = NumToStr(nspoid) + wxT("::oid");
						delete seqcat;
					} else
					{
						lastResultError = sourceconn->GetLastResultError();
						lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
						return;
					}
				}

				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 = ") + oidstr +
					wxT(" AND relname = '") + seqname + wxT("'\n"));
				if (seqcat)
				{
					comment = seqcat->GetVal(wxT("description"));
					owner = seqcat->GetVal(wxT("seqowner"));
					acl = seqcat->GetVal(wxT("relacl"));
					delete seqcat;
				} else
				{
					lastResultError = sourceconn->GetLastResultError();
					lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
					return;
				}
				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
				{
					lastResultError = sourceconn->GetLastResultError();
					lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
					return;
				}

				wxString QuotedFullIdentifier = targetschema->GetQuotedIdentifier() + wxT(".");
				QuotedFullIdentifier += seqname;
				wxString sql = wxT("-- Sequence: ") + QuotedFullIdentifier + wxT("\n\n")
					+ wxT("-- DROP SEQUENCE ") + QuotedFullIdentifier + wxT(";")
					+ wxT("\n\nCREATE SEQUENCE ") + QuotedFullIdentifier
					+ 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 ")
					+ QuotedFullIdentifier + wxT(" OWNER TO ") + qtIdent(owner) + wxT(";\n");
				if (!seq.GetConnection()->BackendMinimumVersion(8, 2))
					sql += seq.GetGrant(wxT("arwdRxt"), wxT("TABLE ") + QuotedFullIdentifier);
				else
					sql += seq.GetGrant(wxT("rwU"), wxT("TABLE ") + QuotedFullIdentifier);
				wxString cmt;
				if (!comment.IsNull())
				{
					cmt = wxT("COMMENT ON SEQUENCE ") + QuotedFullIdentifier
						+ wxT(" IS ") + targetschema->qtDbString(comment) + wxT(";\n");
					sql += cmt;
				}

				rc = targetconn->ExecuteVoid(sql, false);
				if (!rc)
				{
					lastResultError = targetconn->GetLastResultError();
					lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
					return;
				}
			}
		}
	}

	{
		wxString createsql = table1->GetSql(browser);
		createsql.Replace(srcschema->GetQuotedIdentifier() + wxT("."), targetschema->GetQuotedIdentifier() + wxT("."), true);

		wxString createsql1;
		bool nextval = false;
		wxArrayString resarray = stringToArray(createsql, wxT("nextval("));
		if (resarray.Count() > 1)
		{
			for(unsigned int j = 0; j < resarray.Count(); j++)
			{
				wxString token = resarray.Item(j);
				if (token == wxT("nextval("))
				{
					createsql1 += token;
					nextval = true;
				}
				else
				{
					if (!nextval)
					{
						createsql1 += token;
						continue;
					}
					else
					{
						nextval = false;
						int pos = token.find(wxT("'::text)"));
						if (pos == wxNOT_FOUND)
						{
							pos = token.find(wxT("'::regclass)"));
							if (pos == wxNOT_FOUND)
							{
								createsql1 += token;
								continue;
							}
						}
						wxString token1 = token.Mid(0, pos);
						bool haspar = false;
						if (token1.StartsWith(wxT("(")))
						{
							token1 = token1.Mid(1);
							haspar = true;
						}
						token1 = token1.Mid(1);
						wxString token2 = token1;
						token2.Replace(wxT("\"\""), wxT("  "), true);
						int subseq = token2.Find(wxT("\"."));
						if (subseq == wxNOT_FOUND)
						{
							int subseq = token2.Find(wxT("."));
							if (subseq == wxNOT_FOUND)
							{
								token1 = targetschema->GetQuotedIdentifier() + wxT(".") + token1;
							}
							else
							{
								token1 = targetschema->GetQuotedIdentifier() + wxT(".") + token1.Mid(subseq + 1);
							}
						}
						else
						{
							token1 = targetschema->GetQuotedIdentifier() + wxT(".") + token1.Mid(subseq + 2);
						}
						token1.Replace(wxT("'"), wxT("''"), true);
						token1 = wxT("'") + token1;
						if (haspar)
						{
							token1 = wxT("(") + token1;
						}
						token = token1 + token.Mid(pos);
						createsql1 += token;
					}
				}
			}
			createsql = createsql1;
		}

		wxString searchPath = targetconn->ExecuteScalar(wxT("SHOW search_path"));
		createsql = wxT("SET search_path=") + targetschema->GetQuotedIdentifier() + wxT(";") + createsql;
		rc = targetconn->ExecuteVoid(createsql, false);
		if (!rc)
		{
			lastResultError = targetconn->GetLastResultError();
			lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
			return;
		}
		if (!searchPath.IsEmpty())
		{
			rc = targetconn->ExecuteVoid(wxT("SET search_path=") + searchPath, false);
			if (!rc)
			{
				lastResultError = targetconn->GetLastResultError();
				lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
				return;
			}
		}

		if (sourceconn->GetDbname() == targetconn->GetDbname() && sourceconn->GetHost() == 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)
			{
				lastResultError = targetconn->GetLastResultError();
				lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
				return;
			}
		}
		else
		{
			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;
			}
			wxString copysql =
				wxT("COPY ")
				+ srcschema->GetQuotedPrefix() + table1->GetQuotedIdentifier()
				+ wxT(" TO STDOUT");
			do_copy(sourceconn, copysql, tmpFile);
			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;
				}
				copysql =
					wxT("COPY ")
					+ targetschema->GetQuotedPrefix() + table1->GetQuotedIdentifier()
					+ wxT(" FROM STDIN");
				do_copy(targetconn, copysql, tmpFile);
			}
			tmpFile.Close();
			wxRemoveFile(tmpFilename);
		}
	}
}

void frmPasteObject::process()
{
	if (!sourceobj || !targetobj)
	{
		return;
	}

	wxArrayString srcObjArray;
	pgSchema *targetschema = (pgSchema *)targetobj;
	pgSchema *srcschema = 0;
	//tree item 'Tables' has GetMetaType() == PGM_TABLE !
	pgTable *table = (sourceobj->GetMetaType() == PGM_TABLE) ? dynamic_cast<pgTable *>(sourceobj) : 0;
	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;
		}
	}
	else
	{
		//tree item 'Schemas' has GetMetaType() == PGM_SCHEMA !
		srcschema = dynamic_cast<pgSchema *>(sourceobj);
		if (!srcschema) {
			//tree item 'Tables' has GetMetaType() == PGM_TABLE or
			//tree item 'Schemas' has GetMetaType() == PGM_SCHEMA !
			return;
		}
		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;
			}
	}

	pgConn *sourceconn = sourceobj->GetConnection();
	pgConn *targetconn = targetobj->GetConnection();

	if (!sourceconn || !targetconn)
	{
		wxMessageBox(
			_("Both source and target schema connections should be established before paste table(s) operation !"));
		return;
	}

	if (srcschema)
	{
		srcObjArray = getSchemaTables(srcschema);
	}
	else
	{
		srcObjArray.Add(table->GetIdentifier());
		srcschema = table->GetSchema();
	}

	if (srcschema->GetQuotedIdentifier() == targetschema->GetQuotedIdentifier())
	{
		wxMessageBox(_("Source and target schema should be different schema for paste table(s) operation !"));
		return;
	}

	srcschema->ShowTreeDetail(mainform->GetBrowser());

	wxString msg;
	int copied = 0;
	for(unsigned int i = 0; i < srcObjArray.Count(); i++)
	{
		pastemsg = _("COPY TABLE:") +
			srcschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + srcschema->GetQuotedIdentifier() + wxT(".") +
			srcObjArray.Item(i) +
			_(" INTO:") + targetschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + targetschema->GetQuotedIdentifier();
		mainform->GetStatusBar()->SetStatusText(pastemsg, 1);
		pastemsg = _("COPY TABLE:\n") +
			srcschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + srcschema->GetQuotedIdentifier() + wxT(".") +
			srcObjArray.Item(i) +
			_("\nINTO:\n") + targetschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + targetschema->GetQuotedIdentifier();

		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()->GetQuotedIdentifier() + wxT(".") + srcschema->GetQuotedIdentifier() + wxT(".") +
				srcObjArray.Item(i);
			continue;
		}
		else
		{
			copyTable(mainform->GetBrowser(), srcschema, targetschema, table1);
			if (lastResultError.formatted_msg == wxT("TABLE EXISTS"))
			{
				continue;
			}
			if (lastResultError.formatted_msg.IsEmpty())
			{
				targetschema->GetConnection()->ExecuteVoid(wxT("COMMIT"));
				lastResultError = targetschema->GetConnection()->GetLastResultError();
				if (!lastResultError.formatted_msg.IsEmpty())
				{
					lastResultError.formatted_msg = pastemsg + wxT("\n") + lastResultError.formatted_msg;
					msg = lastResultError.formatted_msg;
				}
			}
			else
			{
				targetschema->GetConnection()->ExecuteVoid(wxT("ROLLBACK"));
				msg = lastResultError.formatted_msg;
			}
			if (!lastResultError.formatted_msg.IsEmpty())
			{
				wxMessageBox(msg,
					_("Cannot paste table:") +
					targetschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + targetschema->GetQuotedIdentifier() +
					wxT(".") + table1->GetQuotedIdentifier(),
					wxOK | wxICON_ERROR);
				continue;
			}
		}
		copied++;
	}
	msg = wxString::Format(_("%d of %d TABLE(s) COPIED FROM %s TO %s"), copied, srcObjArray.Count(),
		(srcschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + srcschema->GetQuotedIdentifier()).c_str(),
		(targetschema->GetDatabase()->GetQuotedIdentifier() + wxT(".") + targetschema->GetQuotedIdentifier()).c_str());
	if (copied) {
		mainform->Refresh(targetobj);
	}
	mainform->GetStatusBar()->SetStatusText(msg, 1);
}

frmPasteObject::~frmPasteObject()
{
}
//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2011, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// frmPasteObject.h - Copy/Paste object functions
//
//////////////////////////////////////////////////////////////////////////

#ifndef FRMPASTEOBJECT_H
#define	FRMPASTEOBJECT_H

#include <wx/wx.h>

#include "pgAdmin3.h"
#include "frm/frmMain.h"
#include "schema/pgObject.h"
#include "schema/pgSchema.h"
#include "schema/pgTable.h"

class frmPasteObject
{
public:
	frmPasteObject(frmMain *form, pgObject *sourceobj, pgObject *targetobj);
	void process();
	virtual ~frmPasteObject();
private:
	wxArrayString getSchemaTables(pgSchema *srcschema);
	bool tableExists(pgSchema *srcschema, wxString quotedtablename);
	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);
	wxArrayString stringToArray(wxString & src, wxString pattern);
	void copyTable(ctlTree *browser, pgSchema *srcschema, pgSchema *targetschema, pgTable *table1);

	frmMain  *mainform;
	pgObject *sourceobj;
	pgObject *targetobj;
	pgError  lastResultError;
	wxString pastemsg;
};

#endif	/* FRMPASTEOBJECT_H */

Attachment: pgColumn.cpp.diff
Description: Binary data

Attachment: pgConn.cpp.diff
Description: Binary data

Attachment: pgConn.h.diff
Description: Binary data

-- 
Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers

Reply via email to