mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
230 lines
5.8 KiB
C++
230 lines
5.8 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgScript - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#include "pgAdmin3.h"
|
|
#include "pgscript/expressions/pgsExecute.h"
|
|
|
|
#include <wx/regex.h>
|
|
#include "db/pgConn.h"
|
|
#include "db/pgQueryThread.h"
|
|
#include "pgscript/objects/pgsNumber.h"
|
|
#include "pgscript/objects/pgsRecord.h"
|
|
#include "pgscript/objects/pgsString.h"
|
|
#include "pgscript/utilities/pgsUtilities.h"
|
|
#include "pgscript/utilities/pgsThread.h"
|
|
|
|
pgsExecute::pgsExecute(const wxString &query, pgsOutputStream *cout,
|
|
pgsThread *app) :
|
|
pgsExpression(), m_query(query), m_cout(cout), m_app(app)
|
|
{
|
|
|
|
}
|
|
|
|
pgsExecute::~pgsExecute()
|
|
{
|
|
|
|
}
|
|
|
|
pgsExpression *pgsExecute::clone() const
|
|
{
|
|
return pnew pgsExecute(*this);
|
|
}
|
|
|
|
pgsExecute &pgsExecute::operator=(const pgsExecute &that)
|
|
{
|
|
if (this != &that)
|
|
{
|
|
pgsExpression::operator=(that);
|
|
m_query = that.m_query;
|
|
m_app = that.m_app;
|
|
m_query = that.m_query;
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
wxString pgsExecute::value() const
|
|
{
|
|
return m_query;
|
|
}
|
|
|
|
pgsOperand pgsExecute::eval(pgsVarMap &vars) const
|
|
{
|
|
// Copy statement locally
|
|
wxString stmt(m_query);
|
|
|
|
// Build regular expressions
|
|
wxRegEx identifier(wxT("([^\\\\])(@[a-zA-Z0-9_#@]+)"));
|
|
wxRegEx escaped(wxT("\\\\(@|\\\\)")); // Backslash followed by @ or backslash
|
|
wxASSERT(identifier.IsValid() && escaped.IsValid());
|
|
|
|
// Replace variables in statement
|
|
while (identifier.Matches(stmt))
|
|
{
|
|
wxString var = identifier.GetMatch(stmt, 2);
|
|
wxString chr = identifier.GetMatch(stmt, 1);
|
|
if (vars.find(var) != vars.end())
|
|
{
|
|
wxString res = vars[var]->eval(vars)->value();
|
|
identifier.ReplaceFirst(&stmt, chr + pgsUtilities::escape_quotes(res));
|
|
}
|
|
else
|
|
{
|
|
identifier.ReplaceFirst(&stmt, chr + wxT("\\\\") + var);
|
|
}
|
|
}
|
|
escaped.ReplaceAll(&stmt, wxT("\\1"));
|
|
|
|
// Perform operations only if we have a valid connection
|
|
if (m_app != 0 && m_app->connection() != 0 && !m_app->TestDestroy())
|
|
{
|
|
pgQueryThread thread(m_app->connection(), stmt);
|
|
|
|
if (thread.Create() == wxTHREAD_NO_ERROR)
|
|
{
|
|
if (thread.Run() == wxTHREAD_NO_ERROR)
|
|
{
|
|
while (true)
|
|
{
|
|
if (m_app->TestDestroy()) // wxThread::TestDestroy()
|
|
{
|
|
thread.Delete();
|
|
break;
|
|
}
|
|
else if (thread.IsRunning())
|
|
{
|
|
m_app->Yield();
|
|
m_app->Sleep(20);
|
|
}
|
|
else
|
|
{
|
|
thread.Wait();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (thread.ReturnCode() != PGRES_COMMAND_OK
|
|
&& thread.ReturnCode() != PGRES_TUPLES_OK)
|
|
{
|
|
if (m_cout != 0)
|
|
{
|
|
m_app->LockOutput();
|
|
|
|
(*m_cout) << PGSOUTWARNING;
|
|
wxString message(stmt + wxT("\n") + thread
|
|
.GetMessagesAndClear().Strip(wxString::both));
|
|
wxRegEx multilf(wxT("(\n)+"));
|
|
multilf.ReplaceAll(&message, wxT("\n"));
|
|
message.Replace(wxT("\n"), wxT("\n")
|
|
+ generate_spaces(PGSOUTWARNING.Length()));
|
|
(*m_cout) << message << wxT("\n");
|
|
|
|
m_app->UnlockOutput();
|
|
}
|
|
}
|
|
else if (!m_app->TestDestroy())
|
|
{
|
|
if (m_cout != 0)
|
|
{
|
|
m_app->LockOutput();
|
|
|
|
(*m_cout) << PGSOUTQUERY;
|
|
wxString message(thread.GetMessagesAndClear()
|
|
.Strip(wxString::both));
|
|
if (!message.IsEmpty())
|
|
message = stmt + wxT("\n") + message;
|
|
else
|
|
message = stmt;
|
|
wxRegEx multilf(wxT("(\n)+"));
|
|
multilf.ReplaceAll(&message, wxT("\n"));
|
|
message.Replace(wxT("\n"), wxT("\n")
|
|
+ generate_spaces(PGSOUTQUERY.Length()));
|
|
(*m_cout) << message << wxT("\n");
|
|
|
|
m_app->UnlockOutput();
|
|
}
|
|
|
|
pgsRecord *rec = 0;
|
|
|
|
if (thread.DataValid())
|
|
{
|
|
pgSet *set = thread.DataSet();
|
|
set->MoveFirst();
|
|
rec = pnew pgsRecord(set->NumCols());
|
|
wxArrayLong columns_int; // List of columns that contain integers
|
|
wxArrayLong columns_real; // List of columns that contain reals
|
|
for (long i = 0; i < set->NumCols(); i++)
|
|
{
|
|
rec->set_column_name(i, set->ColName(i));
|
|
wxString col_type = set->ColType(i);
|
|
if (!col_type.CmpNoCase(wxT("bigint"))
|
|
|| !col_type.CmpNoCase(wxT("smallint"))
|
|
|| !col_type.CmpNoCase(wxT("integer")))
|
|
{
|
|
columns_int.Add(i);
|
|
}
|
|
else if (!col_type.CmpNoCase(wxT("real"))
|
|
|| !col_type.CmpNoCase(wxT("double precision"))
|
|
|| !col_type.CmpNoCase(wxT("money"))
|
|
|| !col_type.CmpNoCase(wxT("numeric")))
|
|
{
|
|
columns_real.Add(i);
|
|
}
|
|
}
|
|
size_t line = 0;
|
|
while (!set->Eof())
|
|
{
|
|
for (long i = 0; i < set->NumCols(); i++)
|
|
{
|
|
wxString value = set->GetVal(i);
|
|
|
|
if (columns_int.Index(i) != wxNOT_FOUND
|
|
&& pgsNumber::num_type(value) == pgsNumber::pgsTInt)
|
|
{
|
|
rec->insert(line, i, pnew pgsNumber(value, pgsInt));
|
|
}
|
|
else if (columns_real.Index(i) != wxNOT_FOUND
|
|
&& pgsNumber::num_type(value) == pgsNumber::pgsTReal)
|
|
{
|
|
rec->insert(line, i, pnew pgsNumber(value, pgsReal));
|
|
}
|
|
else
|
|
{
|
|
rec->insert(line, i, pnew pgsString(value));
|
|
}
|
|
}
|
|
set->MoveNext();
|
|
++line;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rec = pnew pgsRecord(1);
|
|
rec->insert(0, 0, pnew pgsNumber(wxT("1")));
|
|
}
|
|
|
|
return rec;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxLogError(wxT("PGSCRIPT: Cannot run query thread for the query:\n%s"),
|
|
m_query.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxLogError(wxT("PGSCRIPT: Cannot create query thread for the query:\n%s"),
|
|
m_query.c_str());
|
|
}
|
|
}
|
|
|
|
// This must return a record whatever happens
|
|
return pnew pgsRecord(1);
|
|
}
|