pgadmin3/db/pgSet.cpp
lsv debed953cf Performance improvement and usability
Повышение производительности вывода результатов запроса и дерева объектов.
Мелкие исправления.
2023-06-29 21:00:44 +05:00

442 lines
7.7 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// pgSet.cpp - PostgreSQL ResultSet class
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin3.h"
// wxWindows headers
#include <wx/wx.h>
// PostgreSQL headers
#include <libpq-fe.h>
// App headers
#include "db/pgSet.h"
#include "db/pgConn.h"
#include "utils/sysLogger.h"
#include "utils/pgDefs.h"
pgSet::pgSet()
: conv(wxConvLibc)
{
conn = 0;
res = 0;
nCols = 0;
nRows = 0;
pos = 0;
}
pgSet::pgSet(PGresult *newRes, pgConn *newConn, wxMBConv &cnv, bool needColQt)
: conv(cnv)
{
needColQuoting = needColQt;
conn = newConn;
res = newRes;
// Make sure we have tuples
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
nCols = 0;
nRows = 0;
pos = 0;
}
else
{
nCols = PQnfields(res);
for (int x = 0; x < nCols + 1; x++)
{
colTypes.Add(wxT(""));
colFullTypes.Add(wxT(""));
colClasses.Add(0);
}
nRows = PQntuples(res);
MoveFirst();
}
}
pgSet::~pgSet()
{
PQclear(res);
}
OID pgSet::ColTypeOid(const int col) const
{
wxASSERT(col < nCols && col >= 0);
return PQftype(res, col);
}
long pgSet::ColTypeMod(const int col) const
{
wxASSERT(col < nCols && col >= 0);
return PQfmod(res, col);
}
long pgSet::GetInsertedCount() const
{
char *cnt = PQcmdTuples(res);
if (!*cnt)
return -1;
else
return atol(cnt);
}
pgTypClass pgSet::ColTypClass(const int col) const
{
wxASSERT(col < nCols && col >= 0);
if (colClasses[col] != 0)
return (pgTypClass)colClasses[col];
wxString typoid = ExecuteScalar(
wxT("SELECT CASE WHEN typbasetype=0 THEN oid else typbasetype END AS basetype\n")
wxT(" FROM pg_type WHERE oid=") + NumToStr(ColTypeOid(col)));
switch (StrToLong(typoid))
{
case PGOID_TYPE_BOOL:
colClasses[col] = PGTYPCLASS_BOOL;
break;
case PGOID_TYPE_INT8:
case PGOID_TYPE_INT2:
case PGOID_TYPE_INT4:
case PGOID_TYPE_OID:
case PGOID_TYPE_XID:
case PGOID_TYPE_TID:
case PGOID_TYPE_CID:
case PGOID_TYPE_FLOAT4:
case PGOID_TYPE_FLOAT8:
case PGOID_TYPE_MONEY:
case PGOID_TYPE_BIT:
case PGOID_TYPE_NUMERIC:
colClasses[col] = PGTYPCLASS_NUMERIC;
break;
case PGOID_TYPE_BYTEA:
case PGOID_TYPE_CHAR:
case PGOID_TYPE_NAME:
case PGOID_TYPE_TEXT:
case PGOID_TYPE_VARCHAR:
colClasses[col] = PGTYPCLASS_STRING;
break;
case PGOID_TYPE_TIMESTAMP:
case PGOID_TYPE_TIMESTAMPTZ:
case PGOID_TYPE_TIME:
case PGOID_TYPE_TIMETZ:
case PGOID_TYPE_INTERVAL:
colClasses[col] = PGTYPCLASS_DATE;
break;
default:
colClasses[col] = PGTYPCLASS_OTHER;
break;
}
return (pgTypClass)colClasses[col];
}
wxString pgSet::ColType(const int col) const
{
wxASSERT(col < nCols && col >= 0);
if (!colTypes[col].IsEmpty())
return colTypes[col];
wxString szSQL, szResult;
szSQL.Printf(wxT("SELECT format_type(oid,NULL) as typname FROM pg_type WHERE oid = %d"), (int)ColTypeOid(col));
szResult = ExecuteScalar(szSQL);
colTypes[col] = szResult;
return szResult;
}
wxString pgSet::ColFullType(const int col) const
{
wxASSERT(col < nCols && col >= 0);
if (!colFullTypes[col].IsEmpty())
return colFullTypes[col];
wxString szSQL, szResult;
szSQL.Printf(wxT("SELECT format_type(oid,%d) as typname FROM pg_type WHERE oid = %d"), (int)ColTypeMod(col), (int)ColTypeOid(col));
szResult = ExecuteScalar(szSQL);
colFullTypes[col] = szResult;
return szResult;
}
int pgSet::ColScale(const int col) const
{
wxASSERT(col < nCols && col >= 0);
// TODO
return 0;
}
wxString pgSet::ColName(const int col) const
{
wxASSERT(col < nCols && col >= 0);
return wxString(PQfname(res, col), conv);
}
int pgSet::ColNumber(const wxString &colname) const
{
int col;
col = PQfnumber(res, colname.mb_str(conv));
if (col < 0 && needColQuoting)
{
wxString quotedColName = colname;
quotedColName.Replace(wxT("\""), wxT("\"\""));
col = PQfnumber(res, (wxT("\"") + quotedColName + wxT("\"")).mb_str(conv));
}
if (col < 0)
{
wxLogError(__("Column not found in pgSet: %s"), colname.c_str());
}
return col;
}
bool pgSet::HasColumn(const wxString &colname) const
{
if (needColQuoting)
{
wxString quotedColName = colname;
quotedColName.Replace(wxT("\""), wxT("\"\""));
return (PQfnumber(res, (wxT("\"") + quotedColName + wxT("\"")).mb_str(conv)) < 0 ? false : true);
}
else
return (PQfnumber(res, colname.mb_str(conv)) < 0 ? false : true);
}
char *pgSet::GetCharPtr(const int col) const
{
wxASSERT(col < nCols && col >= 0);
return PQgetvalue(res, pos - 1, col);
}
char *pgSet::GetCharPtr(const wxString &col) const
{
return PQgetvalue(res, pos - 1, ColNumber(col));
}
wxString pgSet::GetVal(const int col) const
{
wxASSERT(col < nCols && col >= 0);
return wxString(GetCharPtr(col), conv);
}
wxString pgSet::GetVal(const wxString &colname) const
{
return GetVal(ColNumber(colname));
}
long pgSet::GetLong(const int col) const
{
wxASSERT(col < nCols && col >= 0);
char *c = PQgetvalue(res, pos - 1, col);
if (c)
return atol(c);
else
return 0;
}
long pgSet::GetLong(const wxString &col) const
{
char *c = PQgetvalue(res, pos - 1, ColNumber(col));
if (c)
return atol(c);
else
return 0;
}
bool pgSet::GetBool(const int col) const
{
wxASSERT(col < nCols && col >= 0);
char *c = PQgetvalue(res, pos - 1, col);
if (c)
{
if (*c == 't' || *c == '1' || !strcmp(c, "on"))
return true;
}
return false;
}
bool pgSet::GetBool(const wxString &col) const
{
return GetBool(ColNumber(col));
}
wxDateTime pgSet::GetDateTime(const int col) const
{
wxASSERT(col < nCols && col >= 0);
wxDateTime dt((time_t)-1);
wxString str = GetVal(col);
/* This hasn't just been used. ( Is not infinity ) */
if (!str.IsEmpty())
dt.ParseDateTime(str);
return dt;
}
wxDateTime pgSet::GetDateTime(const wxString &col) const
{
return GetDateTime(ColNumber(col));
}
wxDateTime pgSet::GetDate(const int col) const
{
wxASSERT(col < nCols && col >= 0);
wxDateTime dt;
wxString str = GetVal(col);
/* This hasn't just been used. ( Is not infinity ) */
if (!str.IsEmpty())
dt.ParseDate(str);
return dt;
}
wxDateTime pgSet::GetDate(const wxString &col) const
{
return GetDate(ColNumber(col));
}
double pgSet::GetDouble(const int col) const
{
wxASSERT(col < nCols && col >= 0);
return StrToDouble(GetVal(col));
}
double pgSet::GetDouble(const wxString &col) const
{
return GetDouble(ColNumber(col));
}
wxULongLong pgSet::GetLongLong(const int col) const
{
wxASSERT(col < nCols && col >= 0);
char *c = PQgetvalue(res, pos - 1, col);
if (c)
return atolonglong(c);
else
return 0;
}
wxULongLong pgSet::GetLongLong(const wxString &col) const
{
return GetLongLong(ColNumber(col));
}
OID pgSet::GetOid(const int col) const
{
wxASSERT(col < nCols && col >= 0);
char *c = PQgetvalue(res, pos - 1, col);
if (c)
return (OID)strtoul(c, 0, 10);
else
return 0;
}
OID pgSet::GetOid(const wxString &col) const
{
return GetOid(ColNumber(col));
}
wxString pgSet::ExecuteScalar(const wxString &sql) const
{
return conn->ExecuteScalar(sql);
}
//////////////////////////////////////////////////////////////////
pgSetIterator::pgSetIterator(pgConn *conn, const wxString &qry)
{
set = conn->ExecuteSet(qry);
first = true;
}
pgSetIterator::pgSetIterator(pgSet *s)
{
set = s;
first = true;
}
pgSetIterator::~pgSetIterator()
{
if (set)
delete set;
}
bool pgSetIterator::RowsLeft()
{
if (!set)
return false;
if (first)
{
if (!set->NumRows())
return false;
first = false;
}
else
set->MoveNext();
return !set->Eof();
}
bool pgSetIterator::MovePrev()
{
if (!set)
return false;
set->MovePrevious();
return true;
}