////////////////////////////////////////////////////////////////////////// // // 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 // PostgreSQL headers #include // 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; }