Reorganize files in pglablib
The enitities and containers of the catalog now go into catalog subfolder Models go into model
This commit is contained in:
parent
56cbeea183
commit
f0c1035378
121 changed files with 226 additions and 183 deletions
6
pglablib/catalog/PgAm.cpp
Normal file
6
pglablib/catalog/PgAm.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "PgAm.h"
|
||||
|
||||
PgAm::PgAm()
|
||||
{
|
||||
|
||||
}
|
||||
19
pglablib/catalog/PgAm.h
Normal file
19
pglablib/catalog/PgAm.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef PGAM_H
|
||||
#define PGAM_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QString>
|
||||
|
||||
class PgAm {
|
||||
public:
|
||||
Oid oid;
|
||||
QString name;
|
||||
|
||||
PgAm();
|
||||
|
||||
bool operator==(Oid rhs) const { return oid == rhs; }
|
||||
bool operator<(Oid rhs) const { return oid < rhs; }
|
||||
bool operator<(const PgAm &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGAM_H
|
||||
17
pglablib/catalog/PgAmContainer.cpp
Normal file
17
pglablib/catalog/PgAmContainer.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include "PgAmContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
std::string PgAmContainer::getLoadQuery() const
|
||||
{
|
||||
std::string q = "SELECT oid, amname FROM pg_am";
|
||||
return q;
|
||||
}
|
||||
|
||||
PgAm PgAmContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgAm v;
|
||||
col >> v.oid >> v.name;
|
||||
|
||||
return v;
|
||||
}
|
||||
18
pglablib/catalog/PgAmContainer.h
Normal file
18
pglablib/catalog/PgAmContainer.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef PGAMCONTAINER_H
|
||||
#define PGAMCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgAm.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <vector>
|
||||
|
||||
class PgAmContainer : public PgContainer<PgAm> {
|
||||
public:
|
||||
using PgContainer<PgAm>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
virtual PgAm loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
#endif // PGAMCONTAINER_H
|
||||
56
pglablib/catalog/PgAttribute.cpp
Normal file
56
pglablib/catalog/PgAttribute.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "PgAttribute.h"
|
||||
#include "QStringBuilder"
|
||||
#include "SqlFormattingUtils.h"
|
||||
#include "PgClass.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include "PgCollation.h"
|
||||
#include "PgCollationContainer.h"
|
||||
|
||||
QString PgAttribute::columnDefinition(const PgDatabaseCatalog &cat) const
|
||||
{
|
||||
// create: column_name data_type [ COLLATE collation ] [ column_constraint [ ... ]
|
||||
// alter: column_name data_type [ COLLATE collation ] [ column_constraint [ ... ]
|
||||
// constraints NULL/NOT NULL, DEFAULT, GENERATED other constraints will be ignored here a
|
||||
auto&& type = cat.types()->getByKey(typid);
|
||||
|
||||
QString sql = quoteIdent(name) % " " % type->objectName();
|
||||
if (collation != InvalidOid) {
|
||||
auto&& col = cat.collations()->getByKey(collation);
|
||||
QString oname = col->objectName();
|
||||
if (oname != "default")
|
||||
sql += " COLLATE " % quoteIdent(oname);
|
||||
}
|
||||
|
||||
if (notnull)
|
||||
sql += " NOT NULL";
|
||||
|
||||
if (hasdef)
|
||||
sql += " DEFAULT " % defaultValue;
|
||||
|
||||
if (identity != ' ') {
|
||||
sql += " GENERATED ";
|
||||
if (identity == 'a') sql += "ALWAYS";
|
||||
else if (identity == 'd') sql += "BY DEFAULT";
|
||||
sql += " AS IDENTITY";
|
||||
}
|
||||
// TODO sequence options might be missing
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
QString PgAttribute::alterTableAddColumn(const PgDatabaseCatalog &cat, const PgClass &table) const
|
||||
{
|
||||
QString sql = "ALTER TABLE " % table.fullyQualifiedQuotedObjectName()
|
||||
% " ADD COLUMN " % columnDefinition(cat) % ";";
|
||||
return sql;
|
||||
}
|
||||
|
||||
QString PgAttribute::alterTableDropColumn(const PgDatabaseCatalog &cat, const PgClass &table) const
|
||||
{
|
||||
QString sql = "ALTER TABLE " % table.fullyQualifiedQuotedObjectName()
|
||||
% " DROP COLUMN " % quoteIdent(name) % ";";
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
46
pglablib/catalog/PgAttribute.h
Normal file
46
pglablib/catalog/PgAttribute.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef PGATTRIBUTE_H
|
||||
#define PGATTRIBUTE_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include <tuple>
|
||||
|
||||
class PgClass;
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class PgAttribute {
|
||||
public:
|
||||
using Key = std::tuple<Oid, int16_t>;
|
||||
|
||||
Oid relid = InvalidOid;
|
||||
QString name;
|
||||
Oid typid = InvalidOid;
|
||||
int32_t stattarget = 0;
|
||||
int16_t num = 0;
|
||||
int32_t ndims = 0; // array dimensions
|
||||
int32_t typmod = -1;
|
||||
bool notnull = false;
|
||||
bool hasdef = false;
|
||||
char identity = ' ';
|
||||
bool isdropped = false;
|
||||
bool islocal = true;
|
||||
Oid collation = InvalidOid;
|
||||
QString acl;
|
||||
QString options;
|
||||
|
||||
QString defaultValue; ///< Comes from pg_attrdef table
|
||||
|
||||
|
||||
bool operator==(Key _k) const { return relid == std::get<0>(_k) && num == std::get<1>(_k); }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Key _k) const { return relid < std::get<0>(_k) || (relid == std::get<0>(_k) && num < std::get<1>(_k)); }
|
||||
bool operator<(const PgAttribute &rhs) const { return relid < rhs.relid || (relid == rhs.relid && num < rhs.num); }
|
||||
|
||||
/// Return the part of the SQL create statement that can be reused for both the CREATE TABLE and ALTER TABLE ADD COLUMN
|
||||
QString columnDefinition(const PgDatabaseCatalog &cat) const;
|
||||
QString alterTableAddColumn(const PgDatabaseCatalog &cat, const PgClass &table) const;
|
||||
QString alterTableDropColumn(const PgDatabaseCatalog &cat, const PgClass &table) const;
|
||||
};
|
||||
|
||||
#endif // PGATTRIBUTE_H
|
||||
44
pglablib/catalog/PgAttributeContainer.cpp
Normal file
44
pglablib/catalog/PgAttributeContainer.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "PgAttributeContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
|
||||
//SELECT attname, pg_get_expr(adbin, adrelid) AS def_value
|
||||
//FROM pg_attribute
|
||||
// JOIN pg_attrdef ON attrelid=adrelid AND attnum=adnum
|
||||
//WHERE atthasdef=true
|
||||
|
||||
std::string PgAttributeContainer::getLoadQuery() const
|
||||
{
|
||||
std::string q = R"__(
|
||||
SELECT attrelid, attname, atttypid, attstattarget,
|
||||
attnum, attndims, atttypmod, attnotnull, atthasdef, attisdropped,
|
||||
attislocal, attcollation, attacl, attoptions, pg_get_expr(adbin, adrelid) AS def_value)__";
|
||||
if (m_catalog.serverVersion() >= 100000)
|
||||
q += ", attidentity";
|
||||
q +=
|
||||
"\n FROM pg_catalog.pg_attribute \n"
|
||||
" LEFT JOIN pg_attrdef ON attrelid=adrelid AND attnum=adnum";
|
||||
return q;
|
||||
}
|
||||
|
||||
PgAttribute PgAttributeContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgAttribute v;
|
||||
col >> v.relid >> v.name >> v.typid >> v.stattarget
|
||||
>> v.num >> v.ndims >> v.typmod >> v.notnull >> v.hasdef >> v.isdropped
|
||||
>> v.islocal >> v.collation >> v.acl >> v.options >> v.defaultValue;
|
||||
if (m_catalog.serverVersion() >= 100000)
|
||||
col >> v.identity;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<PgAttribute> PgAttributeContainer::getColumnsForRelation(Oid oid) const
|
||||
{
|
||||
std::vector<PgAttribute> result;
|
||||
for (const auto &e : m_container)
|
||||
if (e.relid == oid)
|
||||
result.push_back(e);
|
||||
return result;
|
||||
}
|
||||
20
pglablib/catalog/PgAttributeContainer.h
Normal file
20
pglablib/catalog/PgAttributeContainer.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef PGATTRIBUTECONTAINER_H
|
||||
#define PGATTRIBUTECONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgAttribute.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <vector>
|
||||
|
||||
class PgAttributeContainer : public PgContainer<PgAttribute, PgAttribute::Key> {
|
||||
public:
|
||||
using PgContainer<PgAttribute, PgAttribute::Key>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
|
||||
std::vector<PgAttribute> getColumnsForRelation(Oid oid) const;
|
||||
protected:
|
||||
PgAttribute loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
#endif // PGATTRIBUTECONTAINER_H
|
||||
3
pglablib/catalog/PgAuthId.cpp
Normal file
3
pglablib/catalog/PgAuthId.cpp
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include "PgAuthId.h"
|
||||
|
||||
PgAuthId::PgAuthId() = default;
|
||||
32
pglablib/catalog/PgAuthId.h
Normal file
32
pglablib/catalog/PgAuthId.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef PGAUTHID_H
|
||||
#define PGAUTHID_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
class PgAuthId {
|
||||
public:
|
||||
PgAuthId();
|
||||
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
bool super;
|
||||
bool inherit;
|
||||
bool createRole;
|
||||
bool createDB;
|
||||
bool canlogin;
|
||||
bool replication;
|
||||
bool bypassRls;
|
||||
int connLimit;
|
||||
QDateTime validUntil;
|
||||
|
||||
bool valid() const { return oid != InvalidOid; }
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgAuthId &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGAUTHID_H
|
||||
27
pglablib/catalog/PgAuthIdContainer.cpp
Normal file
27
pglablib/catalog/PgAuthIdContainer.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include "PgAuthIdContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
std::string PgAuthIdContainer::getLoadQuery() const
|
||||
{
|
||||
std::string result =
|
||||
"SELECT oid, rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, "
|
||||
" rolcanlogin, rolreplication, rolconnlimit, rolvaliduntil";
|
||||
if (minimumVersion(90500))
|
||||
result += ", rolbypassrls";
|
||||
|
||||
result += "\n"
|
||||
"FROM pg_authid";
|
||||
return result;
|
||||
}
|
||||
|
||||
PgAuthId PgAuthIdContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgAuthId v;
|
||||
col >> v.oid >> v.name >> v.super >> v.inherit >> v.createRole >> v.createDB
|
||||
>> v.canlogin >> v.replication >> v.connLimit >> v.validUntil;
|
||||
if (minimumVersion(90500))
|
||||
col >> v.bypassRls;
|
||||
|
||||
return v;
|
||||
}
|
||||
25
pglablib/catalog/PgAuthIdContainer.h
Normal file
25
pglablib/catalog/PgAuthIdContainer.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef PGAUTHIDCONTAINER_H
|
||||
#define PGAUTHIDCONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
#include "PgContainer.h"
|
||||
#include "PgAuthId.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
class PgAuthIdContainer: public PgContainer<PgAuthId> {
|
||||
public:
|
||||
using PgContainer<PgAuthId>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
PgAuthId loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGAUTHIDCONTAINER_H
|
||||
13
pglablib/catalog/PgCatalogTypes.h
Normal file
13
pglablib/catalog/PgCatalogTypes.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef PGCATALOGTYPES_H
|
||||
#define PGCATALOGTYPES_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <vector>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
using AttNumVec = std::vector<int16_t>;
|
||||
template<int size>
|
||||
using SmallAttNumVec = boost::container::small_vector<int16_t, size>;
|
||||
using OidVec = std::vector<Oid>;
|
||||
|
||||
#endif // PGCATALOGTYPES_H
|
||||
136
pglablib/catalog/PgClass.cpp
Normal file
136
pglablib/catalog/PgClass.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#include "PgClass.h"
|
||||
#include "PgAttributeContainer.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgConstraintContainer.h"
|
||||
#include "PgInheritsContainer.h"
|
||||
#include <QStringBuilder>
|
||||
#include "SqlFormattingUtils.h"
|
||||
|
||||
|
||||
|
||||
void operator<<(RelPersistence &s, const Pgsql::Value &v)
|
||||
{
|
||||
//s = static_cast<T>(v);
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'p':
|
||||
s = RelPersistence::Permanent;
|
||||
break;
|
||||
case 'u':
|
||||
s = RelPersistence::Unlogged;
|
||||
break;
|
||||
case 't':
|
||||
s = RelPersistence::Temporary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void operator<<(RelKind &s, const Pgsql::Value &v)
|
||||
{
|
||||
//s = static_cast<T>(v);
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'r':
|
||||
s = RelKind::Table;
|
||||
break;
|
||||
case 'i':
|
||||
s = RelKind::Index;
|
||||
break;
|
||||
case 'S':
|
||||
s = RelKind::Sequence;
|
||||
break;
|
||||
case 'v':
|
||||
s = RelKind::View;
|
||||
break;
|
||||
case 'm':
|
||||
s = RelKind::MaterializedView;
|
||||
break;
|
||||
case 'c':
|
||||
s = RelKind::Composite;
|
||||
break;
|
||||
case 't':
|
||||
s = RelKind::Toast;
|
||||
break;
|
||||
case 'f':
|
||||
s = RelKind::ForeignTable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//QString PgClass::objectName() const
|
||||
//{
|
||||
// return name;
|
||||
//}
|
||||
|
||||
QString PgClass::createSql() const
|
||||
{
|
||||
if (createSqlCache.isEmpty()) {
|
||||
if (kind == RelKind::Table)
|
||||
createSqlCache = createTableSql();
|
||||
|
||||
}
|
||||
return createSqlCache;
|
||||
}
|
||||
|
||||
QString PgClass::createTableSql() const
|
||||
{
|
||||
QString sql;
|
||||
// CREATE [ TEMP | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name ( [
|
||||
sql += "CREATE ";
|
||||
if (persistence == RelPersistence::Unlogged)
|
||||
sql += "UNLOGGED ";
|
||||
else if (persistence == RelPersistence::Temporary)
|
||||
sql += "TEMP ";
|
||||
sql += "TABLE ";
|
||||
sql += fullyQualifiedQuotedObjectName();
|
||||
sql += " (\n ";
|
||||
|
||||
auto && cols = catalog().attributes()->getColumnsForRelation(oid());
|
||||
bool first = true;
|
||||
for (auto && col : cols) {
|
||||
if (col.num > 0 && !col.isdropped) {
|
||||
if (first) {
|
||||
sql += "\n ";
|
||||
first = false;
|
||||
}
|
||||
else sql += ",\n ";
|
||||
if (!col.islocal) sql += "-- ";
|
||||
sql += col.columnDefinition(catalog());
|
||||
}
|
||||
// { column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]
|
||||
// | table_constraint
|
||||
// ] )
|
||||
}
|
||||
auto && constraints = catalog().constraints()->getConstraintsForRelation(oid());
|
||||
for (auto && constraint: constraints) {
|
||||
if (first) {
|
||||
sql += "\n ";
|
||||
first = false;
|
||||
}
|
||||
else sql += ",\n ";
|
||||
sql += getConstraintDefinition(catalog(), constraint);
|
||||
}
|
||||
|
||||
sql += ")";
|
||||
{
|
||||
// [ INHERITS ( parent_table [, ... ] ) ]
|
||||
auto parents = catalog().inherits()->getParentsOf(oid());
|
||||
if (!parents.empty()) {
|
||||
sql += "\nINHERITS (";
|
||||
bool first = true;
|
||||
for (auto parent_oid : parents) {
|
||||
if (first) first = false;
|
||||
else sql += ", ";
|
||||
sql += catalog().classes()->getByKey(parent_oid)->fullyQualifiedQuotedObjectName();
|
||||
}
|
||||
sql += ")";
|
||||
}
|
||||
}
|
||||
// [ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ]
|
||||
// [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
|
||||
// [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
|
||||
// [ TABLESPACE tablespace_name ]
|
||||
sql += ";\n";
|
||||
return sql;
|
||||
}
|
||||
76
pglablib/catalog/PgClass.h
Normal file
76
pglablib/catalog/PgClass.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef PGCLASS_H
|
||||
#define PGCLASS_H
|
||||
|
||||
#include "Pgsql_Value.h"
|
||||
#include "PgNamespaceObject.h"
|
||||
#include "PgOwnedObject.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
enum class RelPersistence {
|
||||
Permanent, // p
|
||||
Unlogged, // u
|
||||
Temporary // t
|
||||
};
|
||||
|
||||
void operator<<(RelPersistence &s, const Pgsql::Value &v);
|
||||
|
||||
enum class RelKind {
|
||||
Table, // r
|
||||
Index, // i
|
||||
Sequence, // S
|
||||
View, // v
|
||||
MaterializedView, // m
|
||||
Composite, // c
|
||||
Toast, // t
|
||||
ForeignTable // f
|
||||
};
|
||||
|
||||
void operator<<(RelKind &s, const Pgsql::Value &v);
|
||||
|
||||
|
||||
class PgClass: public PgNamespaceObject, public PgOwnedObject {
|
||||
public:
|
||||
|
||||
// Oid oid = InvalidOid;
|
||||
// QString name;
|
||||
// Oid relnamespace = InvalidOid;
|
||||
// QString relnamespace_name; // Transient, cached value from relnamespace
|
||||
// bool system_namespace = false; // Transient, cached value from relnamespace
|
||||
Oid type = InvalidOid;
|
||||
Oid oftype = InvalidOid;
|
||||
//Oid owner = InvalidOid;
|
||||
Oid am = InvalidOid;
|
||||
Oid filenode = InvalidOid;
|
||||
Oid tablespace = InvalidOid;
|
||||
int32_t pages_est = 0;
|
||||
float tuples_est = 0.0f;
|
||||
Oid toastrelid = InvalidOid;
|
||||
bool isshared = false;
|
||||
RelPersistence persistence;
|
||||
RelKind kind;
|
||||
bool hasoids = false;
|
||||
bool ispopulated;
|
||||
int frozenxid;
|
||||
int minmxid;
|
||||
QString acl;
|
||||
std::vector<QString> options;
|
||||
|
||||
using PgNamespaceObject::PgNamespaceObject;
|
||||
|
||||
// virtual QString objectName() const override;
|
||||
|
||||
// bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
// bool operator==(const QString &n) const { return objectName() == n; }
|
||||
// bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
// bool operator<(const PgClass &rhs) const { return oid < rhs.oid; }
|
||||
|
||||
QString createSql() const;
|
||||
|
||||
private:
|
||||
mutable QString createSqlCache;
|
||||
|
||||
QString createTableSql() const;
|
||||
};
|
||||
|
||||
#endif // PGCLASS_H
|
||||
39
pglablib/catalog/PgClassContainer.cpp
Normal file
39
pglablib/catalog/PgClassContainer.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include "PgClassContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgNamespaceContainer.h"
|
||||
#include <iterator>
|
||||
|
||||
std::string PgClassContainer::getLoadQuery() const
|
||||
{
|
||||
return "SELECT oid, relname, relnamespace, reltype, reloftype, "
|
||||
" relowner, relam, relfilenode, reltablespace, relpages, "
|
||||
" reltuples, reltoastrelid, relisshared, relpersistence, "
|
||||
" relkind, relhasoids, relispopulated, relfrozenxid, relminmxid, "
|
||||
" relacl, reloptions \n"
|
||||
"FROM pg_catalog.pg_class";
|
||||
}
|
||||
|
||||
PgClass PgClassContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
Oid class_oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
Oid schema_oid = col.nextValue();
|
||||
|
||||
PgClass v(m_catalog, class_oid, name, schema_oid);
|
||||
Oid owner ;
|
||||
col >> v.type >> v.oftype
|
||||
>> owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est
|
||||
>> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence
|
||||
>> v.kind >> v.hasoids >> v.ispopulated >> v.frozenxid >> v.minmxid
|
||||
>> v.acl >> v.options;
|
||||
v.setOwnerOid(m_catalog, owner);
|
||||
// auto&& ns = m_catalog.namespaces()->getByKey(v.relnamespace);
|
||||
// if (ns) {
|
||||
// v.relnamespace_name = ns->objectName();
|
||||
// v.system_namespace = ns->isSystemCatalog();
|
||||
// }
|
||||
return v;
|
||||
}
|
||||
24
pglablib/catalog/PgClassContainer.h
Normal file
24
pglablib/catalog/PgClassContainer.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef PGCLASSCONTAINER_H
|
||||
#define PGCLASSCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgClass.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgClassContainer: public PgContainer<PgClass> {
|
||||
public:
|
||||
using PgContainer<PgClass>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
PgClass loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // PGCLASSCONTAINER_H
|
||||
2
pglablib/catalog/PgCollation.cpp
Normal file
2
pglablib/catalog/PgCollation.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#include "PgCollation.h"
|
||||
|
||||
25
pglablib/catalog/PgCollation.h
Normal file
25
pglablib/catalog/PgCollation.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef PGCOLLATION_H
|
||||
#define PGCOLLATION_H
|
||||
|
||||
#include "PgNamespaceObject.h"
|
||||
#include "PgOwnedObject.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include "Pgsql_Value.h"
|
||||
//#include <vector>
|
||||
|
||||
class PgCollation: public PgNamespaceObject, public PgOwnedObject {
|
||||
public:
|
||||
using PgNamespaceObject::PgNamespaceObject;
|
||||
|
||||
// Oid oid; // oid
|
||||
// QString collname; // name
|
||||
// Oid collnamespace; // oid
|
||||
// Oid collowner; // oid
|
||||
int32_t collencoding; // integer
|
||||
QString collcollate; // name
|
||||
QString collctype; // name
|
||||
|
||||
};
|
||||
|
||||
#endif // PGCOLLATION_H
|
||||
28
pglablib/catalog/PgCollationContainer.cpp
Normal file
28
pglablib/catalog/PgCollationContainer.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include "PgCollationContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include <iterator>
|
||||
|
||||
std::string PgCollationContainer::getLoadQuery() const
|
||||
{
|
||||
return "SELECT oid, collname, collnamespace, collowner, collencoding, \n"
|
||||
" collcollate, collctype \n"
|
||||
"FROM pg_collation";
|
||||
}
|
||||
|
||||
PgCollation PgCollationContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
Oid class_oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
Oid ns_oid = col.nextValue();
|
||||
|
||||
PgCollation v(m_catalog, class_oid, name, ns_oid);
|
||||
Oid owner ;
|
||||
|
||||
col >> owner >> v.collencoding >> v.collcollate >> v.collctype;
|
||||
v.setOwnerOid(m_catalog, owner);
|
||||
|
||||
return v;
|
||||
}
|
||||
25
pglablib/catalog/PgCollationContainer.h
Normal file
25
pglablib/catalog/PgCollationContainer.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef PGCOLLATIONCONTAINER_H
|
||||
#define PGCOLLATIONCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgCollation.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgCollationContainer: public PgContainer<PgCollation> {
|
||||
public:
|
||||
using PgContainer<PgCollation>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
PgCollation loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGCOLLATIONCONTAINER_H
|
||||
169
pglablib/catalog/PgConstraint.cpp
Normal file
169
pglablib/catalog/PgConstraint.cpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
#include "PgConstraint.h"
|
||||
|
||||
void operator<<(ConstraintType &s, const Pgsql::Value &v)
|
||||
{
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'c':
|
||||
s = ConstraintType::Check;
|
||||
break;
|
||||
case 'f':
|
||||
s = ConstraintType::ForeignKey;
|
||||
break;
|
||||
case 'p':
|
||||
s = ConstraintType::PrimaryKey;
|
||||
break;
|
||||
case 'u':
|
||||
s = ConstraintType::Unique;
|
||||
break;
|
||||
case 't':
|
||||
s = ConstraintType::ConstraintTrigger;
|
||||
break;
|
||||
case 'x':
|
||||
s = ConstraintType::ExclusionConstraint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString ShortNameForConstraintType(ConstraintType ct)
|
||||
{
|
||||
QString s;
|
||||
switch (ct) {
|
||||
case ConstraintType::Check:
|
||||
s = "C";
|
||||
break;
|
||||
case ConstraintType::ForeignKey:
|
||||
s = "FK";
|
||||
break;
|
||||
case ConstraintType::PrimaryKey:
|
||||
s = "PK";
|
||||
break;
|
||||
case ConstraintType::Unique:
|
||||
s = "U";
|
||||
break;
|
||||
case ConstraintType::ConstraintTrigger:
|
||||
s = "CT";
|
||||
break;
|
||||
case ConstraintType::ExclusionConstraint:
|
||||
s = "XC";
|
||||
break;
|
||||
default:
|
||||
s = "?";
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
QString LongNameForConstraintType(ConstraintType ct)
|
||||
{
|
||||
QString s;
|
||||
switch (ct) {
|
||||
case ConstraintType::Check:
|
||||
s = "check";
|
||||
break;
|
||||
case ConstraintType::ForeignKey:
|
||||
s = "foreign key";
|
||||
break;
|
||||
case ConstraintType::PrimaryKey:
|
||||
s = "primary key";
|
||||
break;
|
||||
case ConstraintType::Unique:
|
||||
s = "unique";
|
||||
break;
|
||||
case ConstraintType::ConstraintTrigger:
|
||||
s = "constraint trigger";
|
||||
break;
|
||||
case ConstraintType::ExclusionConstraint:
|
||||
s = "exclusion constraint";
|
||||
break;
|
||||
default:
|
||||
s = "?";
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void operator<<(ForeignKeyAction &s, const Pgsql::Value &v)
|
||||
{
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'a':
|
||||
s = ForeignKeyAction::NoAction;
|
||||
break;
|
||||
case 'r':
|
||||
s = ForeignKeyAction::Restrict;
|
||||
break;
|
||||
case 'c':
|
||||
s = ForeignKeyAction::Cascade;
|
||||
break;
|
||||
case 'n':
|
||||
s = ForeignKeyAction::SetNull;
|
||||
break;
|
||||
case 'd':
|
||||
s = ForeignKeyAction::SetDefault;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString ForeignKeyActionToString(ForeignKeyAction fka)
|
||||
{
|
||||
QString result;
|
||||
switch (fka) {
|
||||
case ForeignKeyAction::NoAction:
|
||||
result = "NO ACTION";
|
||||
break;
|
||||
case ForeignKeyAction::Restrict:
|
||||
result = "RESTRICT";
|
||||
break;
|
||||
case ForeignKeyAction::Cascade:
|
||||
result = "CASCADE";
|
||||
break;
|
||||
case ForeignKeyAction::SetNull:
|
||||
result = "SET NULL";
|
||||
break;
|
||||
case ForeignKeyAction::SetDefault:
|
||||
result = "SET DEFAULT";
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v)
|
||||
{
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'f':
|
||||
s = ForeignKeyMatch::Full;
|
||||
break;
|
||||
case 'p':
|
||||
s = ForeignKeyMatch::Partial;
|
||||
break;
|
||||
case 's':
|
||||
s = ForeignKeyMatch::Simple;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString ForeignKeyMatchToString(ForeignKeyMatch fkm)
|
||||
{
|
||||
QString result;
|
||||
switch (fkm) {
|
||||
case ForeignKeyMatch::Full :
|
||||
result = "FULL";
|
||||
break;
|
||||
case ForeignKeyMatch::Partial:
|
||||
result = "PARTIAL";
|
||||
break;
|
||||
case ForeignKeyMatch::Simple:
|
||||
result = "SIMPLE";
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//PgConstraint::PgConstraint()
|
||||
//{
|
||||
|
||||
//}
|
||||
81
pglablib/catalog/PgConstraint.h
Normal file
81
pglablib/catalog/PgConstraint.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef PGCONSTRAINT_H
|
||||
#define PGCONSTRAINT_H
|
||||
|
||||
#include "PgNamespaceObject.h"
|
||||
#include "Pgsql_Value.h"
|
||||
#include "PgCatalogTypes.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
enum class ConstraintType {
|
||||
PrimaryKey, // p
|
||||
ForeignKey, // f
|
||||
Unique, // u
|
||||
Check, // c
|
||||
ConstraintTrigger, // t
|
||||
ExclusionConstraint, // x
|
||||
};
|
||||
|
||||
void operator<<(ConstraintType &s, const Pgsql::Value &v);
|
||||
|
||||
QString ShortNameForConstraintType(ConstraintType ct);
|
||||
QString LongNameForConstraintType(ConstraintType ct);
|
||||
|
||||
|
||||
enum class ForeignKeyAction {
|
||||
NoAction, // a
|
||||
Restrict, // r
|
||||
Cascade, // c
|
||||
SetNull, // n
|
||||
SetDefault // d
|
||||
};
|
||||
|
||||
void operator<<(ForeignKeyAction &s, const Pgsql::Value &v);
|
||||
|
||||
QString ForeignKeyActionToString(ForeignKeyAction fka);
|
||||
|
||||
enum class ForeignKeyMatch {
|
||||
Full, // f
|
||||
Partial, // p
|
||||
Simple // s
|
||||
};
|
||||
|
||||
void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v);
|
||||
|
||||
QString ForeignKeyMatchToString(ForeignKeyMatch fkm);
|
||||
|
||||
class PgConstraint: public PgNamespaceObject {
|
||||
public:
|
||||
ConstraintType type;
|
||||
bool deferrable;
|
||||
bool deferred;
|
||||
bool validated;
|
||||
Oid relid = InvalidOid; ///< the table this constraint is on
|
||||
Oid typid = InvalidOid;
|
||||
Oid indid = InvalidOid; ///< index supporting the constraint
|
||||
Oid frelid = InvalidOid; ///< only for FK, referenced table pg_class
|
||||
ForeignKeyAction fupdtype; // on update
|
||||
ForeignKeyAction fdeltype; // on delete
|
||||
ForeignKeyMatch fmatchtype; // match type
|
||||
bool islocal;
|
||||
int32_t inhcount;
|
||||
bool noinherit;
|
||||
SmallAttNumVec<5> key; // list of constraint columns attnum
|
||||
SmallAttNumVec<5> fkey; // fkey list of referenced columns
|
||||
OidVec pfeqop;
|
||||
OidVec ppeqop;
|
||||
OidVec ffeqop;
|
||||
OidVec exclop;
|
||||
QString bin;
|
||||
QString src;
|
||||
|
||||
QString definition;
|
||||
|
||||
using PgNamespaceObject::PgNamespaceObject;
|
||||
};
|
||||
|
||||
|
||||
#endif // PGCONSTRAINT_H
|
||||
75
pglablib/catalog/PgConstraintContainer.cpp
Normal file
75
pglablib/catalog/PgConstraintContainer.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#include "PgConstraintContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include <algorithm>
|
||||
|
||||
std::string PgConstraintContainer::getLoadQuery() const
|
||||
{
|
||||
std::string q = R"__(
|
||||
SELECT oid, conname, connamespace, contype, condeferrable,
|
||||
condeferred, convalidated, conrelid, contypid, conindid,
|
||||
confrelid, confupdtype, confdeltype, confmatchtype,
|
||||
conislocal, coninhcount, connoinherit, conkey, confkey,
|
||||
conpfeqop, conppeqop, conffeqop, conexclop, conbin, consrc,
|
||||
pg_get_constraintdef(oid)
|
||||
FROM pg_constraint)__";
|
||||
|
||||
// auto cat = m_catalog.lock();
|
||||
// if (cat && cat->serverVersion() >= 90400)
|
||||
// q += ", indisreplident ";
|
||||
// q += "\nFROM pg_index";
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PgConstraint PgConstraintContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
using namespace Pgsql;
|
||||
Col col(row);
|
||||
Oid oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
Oid ns_oid = col.nextValue();
|
||||
PgConstraint v(m_catalog, oid, name, ns_oid);
|
||||
col >> v.type >> v.deferrable
|
||||
>> v.deferred >> v.validated >> v.relid >> v.typid >> v.indid
|
||||
>> v.frelid >> v.fupdtype >> v.fdeltype >> v.fmatchtype
|
||||
>> v.islocal >> v.inhcount >> v.noinherit
|
||||
>> v.key >> v.fkey >> v.pfeqop >> v.ppeqop >> v.ffeqop >> v.exclop
|
||||
>> v.bin >> v.src >> v.definition;
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<PgConstraint> PgConstraintContainer::getFKeyForTableColumn(Oid relid, int16_t attnum) const
|
||||
{
|
||||
//const PgConstraint *result = nullptr;
|
||||
std::vector<PgConstraint> result;
|
||||
// WHat do we want to find here? On ly single column constraints or all contstraints.
|
||||
auto res = std::copy_if(m_container.begin(), m_container.end(), std::back_inserter(result),
|
||||
[relid, attnum] (const auto &c) {
|
||||
// the find on v.key may not look super efficient but remember it in general only has one or two elements.
|
||||
return c.type == ConstraintType::ForeignKey && relid == c.relid &&
|
||||
(std::find(c.key.begin(), c.key.end(), attnum) != c.key.end());
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<PgConstraint> PgConstraintContainer::getConstraintsForRelation(Oid relid) const
|
||||
{
|
||||
std::vector<PgConstraint> result;
|
||||
for (const auto &e : m_container)
|
||||
if (e.relid == relid)
|
||||
result.push_back(e);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<PgConstraint> PgConstraintContainer::getPrimaryForRelation(Oid relid) const
|
||||
{
|
||||
std::optional<PgConstraint> result;
|
||||
for (const auto &e : m_container) {
|
||||
if (e.relid == relid && e.type == ConstraintType::PrimaryKey) {
|
||||
result = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
25
pglablib/catalog/PgConstraintContainer.h
Normal file
25
pglablib/catalog/PgConstraintContainer.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef PGCONSTRAINTCONTAINER_H
|
||||
#define PGCONSTRAINTCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgConstraint.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
class PgConstraintContainer : public PgContainer<PgConstraint> {
|
||||
public:
|
||||
using PgContainer<PgConstraint>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
//std::vector<PgConstraint> getIndexesForTable(Oid table_oid) const;
|
||||
std::vector<PgConstraint> getFKeyForTableColumn(Oid relid, int16_t attnum) const;
|
||||
|
||||
std::vector<PgConstraint> getConstraintsForRelation(Oid relid) const;
|
||||
std::optional<PgConstraint> getPrimaryForRelation(Oid relid) const;
|
||||
protected:
|
||||
virtual PgConstraint loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
|
||||
#endif // PGCONSTRAINTCONTAINER_H
|
||||
11
pglablib/catalog/PgContainer.cpp
Normal file
11
pglablib/catalog/PgContainer.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "PgContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
|
||||
IPgContainer::IPgContainer(PgDatabaseCatalog& cat)
|
||||
: m_catalog(cat)
|
||||
{}
|
||||
|
||||
bool IPgContainer::minimumVersion(int required_version) const
|
||||
{
|
||||
return m_catalog.serverVersion() >= required_version;
|
||||
}
|
||||
204
pglablib/catalog/PgContainer.h
Normal file
204
pglablib/catalog/PgContainer.h
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
#ifndef PGCONTAINER_H
|
||||
#define PGCONTAINER_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include "Pgsql_Result.h"
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class IPgContainer {
|
||||
public:
|
||||
IPgContainer(PgDatabaseCatalog& cat);
|
||||
virtual ~IPgContainer() = default;
|
||||
|
||||
virtual std::string getLoadQuery() const = 0;
|
||||
virtual void load(const Pgsql::Result &res) = 0;
|
||||
|
||||
bool minimumVersion(int required_version) const;
|
||||
protected:
|
||||
PgDatabaseCatalog& m_catalog;
|
||||
};
|
||||
|
||||
template<typename T, typename K=Oid>
|
||||
class PgContainer: public IPgContainer {
|
||||
public:
|
||||
using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access
|
||||
|
||||
PgContainer() = default;
|
||||
|
||||
explicit PgContainer(PgDatabaseCatalog& cat)
|
||||
: IPgContainer(cat)
|
||||
{
|
||||
}
|
||||
|
||||
typename t_Container::const_iterator begin() const
|
||||
{
|
||||
return m_container.begin();
|
||||
}
|
||||
|
||||
typename t_Container::const_iterator end() const
|
||||
{
|
||||
return m_container.end();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_container.clear();
|
||||
}
|
||||
|
||||
size_t count() const
|
||||
{
|
||||
return m_container.size();
|
||||
}
|
||||
|
||||
const T* getByKey(const K &key) const
|
||||
{
|
||||
auto lb_result = std::lower_bound(m_container.begin(), m_container.end(), key);
|
||||
if (lb_result != m_container.end() && *lb_result == key)
|
||||
return &*lb_result;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const T* getByName(const QString &name) const
|
||||
{
|
||||
auto find_res = std::find(m_container.begin(), m_container.end(), name);
|
||||
|
||||
if (find_res != m_container.end())
|
||||
return &*find_res;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Retrieve element by index
|
||||
///
|
||||
/// This function throws when idx is out of range
|
||||
/// otherwise it always returns a valid object.
|
||||
const T& getByIdx(int idx) const
|
||||
{
|
||||
return m_container.at(idx);
|
||||
}
|
||||
|
||||
/** Override to implement complete loading logic.
|
||||
*
|
||||
* Do not override this function if you only want to implement
|
||||
* the loading of a single element. Override loadElem instead.
|
||||
*/
|
||||
virtual void load(const Pgsql::Result &res) override
|
||||
{
|
||||
m_container.clear();
|
||||
m_container.reserve(res.rows());
|
||||
for (auto row : res)
|
||||
m_container.push_back(loadElem(row));
|
||||
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
|
||||
// Meant for mocking during testing
|
||||
void add(const T &elem)
|
||||
{
|
||||
m_container.push_back(elem);
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
protected:
|
||||
t_Container m_container;
|
||||
|
||||
/** Override the implementation for this function to implement loading of single row.
|
||||
*
|
||||
* When overriding this function there is no need to override load.
|
||||
*/
|
||||
virtual T loadElem(const Pgsql::Row &) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename T, typename K=Oid>
|
||||
class PgSPtrContainer: public IPgContainer {
|
||||
public:
|
||||
using t_Elem = std::shared_ptr<T>;
|
||||
using t_Container = std::vector<t_Elem>; ///< Do not assume it will stay a vector only expect bidirectional access
|
||||
|
||||
explicit PgSPtrContainer(std::weak_ptr<PgDatabaseCatalog> cat)
|
||||
: m_catalog(cat)
|
||||
{}
|
||||
|
||||
|
||||
typename t_Container::const_iterator begin() const
|
||||
{
|
||||
return m_container.begin();
|
||||
}
|
||||
|
||||
typename t_Container::const_iterator end() const
|
||||
{
|
||||
return m_container.end();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_container.clear();
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
return (int)m_container.size();
|
||||
}
|
||||
|
||||
const t_Elem getByKey(const K &key) const
|
||||
{
|
||||
auto lb_result = std::lower_bound(m_container.begin(), m_container.end(), key);
|
||||
if (lb_result != m_container.end() && **lb_result == key)
|
||||
return *lb_result;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const t_Elem getByName(const QString name) const
|
||||
{
|
||||
auto find_res = std::find_if(m_container.begin(), m_container.end(),
|
||||
[name](auto e) -> bool { return *e = name; } );
|
||||
|
||||
if (find_res != m_container.end())
|
||||
return *find_res;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const t_Elem getByIdx(int idx) const
|
||||
{
|
||||
return m_container.at(idx);
|
||||
}
|
||||
|
||||
/** Override to implement complete loading logic.
|
||||
*
|
||||
* Do not override this function if you only want to implement
|
||||
* the loading of a single element. Override loadElem instead.
|
||||
*/
|
||||
virtual void load(const Pgsql::Result &res) override
|
||||
{
|
||||
m_container.clear();
|
||||
m_container.reserve(res.rows());
|
||||
for (auto row : res)
|
||||
m_container.push_back(loadElem(row));
|
||||
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
protected:
|
||||
std::weak_ptr<PgDatabaseCatalog> m_catalog;
|
||||
t_Container m_container;
|
||||
|
||||
/** Override the implementation for this function to implement loading of single row.
|
||||
*
|
||||
* When overriding this function there is no need to override load.
|
||||
*/
|
||||
virtual t_Elem loadElem(const Pgsql::Row &) = 0;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PGCONTAINER_H
|
||||
2
pglablib/catalog/PgDatabase.cpp
Normal file
2
pglablib/catalog/PgDatabase.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#include "PgDatabase.h"
|
||||
|
||||
33
pglablib/catalog/PgDatabase.h
Normal file
33
pglablib/catalog/PgDatabase.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef PGDATABASE_H
|
||||
#define PGDATABASE_H
|
||||
|
||||
#include "PgServerObject.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgDatabase: public PgServerObject {
|
||||
public:
|
||||
|
||||
// Oid oid = InvalidOid;
|
||||
// QString name;
|
||||
Oid dba; // owner?
|
||||
int encoding;
|
||||
QString collate;
|
||||
QString ctype;
|
||||
bool isTemplate;
|
||||
bool allowConn;
|
||||
int connLimit;
|
||||
Oid tablespace;
|
||||
QString acl;//"ARRAY";"YES"
|
||||
|
||||
using PgServerObject::PgServerObject;
|
||||
|
||||
bool isValid() const { return oid() != InvalidOid; }
|
||||
|
||||
// bool operator==(Oid _oid) const { return oid() == _oid; }
|
||||
// bool operator==(const QString &n) const { return objectName() == n; }
|
||||
// bool operator<(Oid _oid) const { return oid() < _oid; }
|
||||
// bool operator<(const PgDatabase &rhs) const { return oid() < rhs.oid(); }
|
||||
};
|
||||
|
||||
#endif // PGDATABASE_H
|
||||
304
pglablib/catalog/PgDatabaseCatalog.cpp
Normal file
304
pglablib/catalog/PgDatabaseCatalog.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
#include "PgDatabaseCatalog.h"
|
||||
|
||||
#include "ASyncDBConnection.h"
|
||||
#include "PgAmContainer.h"
|
||||
#include "PgAttributeContainer.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgConstraintContainer.h"
|
||||
#include "PgDatabaseContainer.h"
|
||||
#include "PgIndexContainer.h"
|
||||
#include "PgNamespaceContainer.h"
|
||||
#include "PgTablespaceContainer.h"
|
||||
#include "PgTriggerContainer.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include "PgProcContainer.h"
|
||||
#include "PgCollationContainer.h"
|
||||
#include "PgInheritsContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_oids.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
|
||||
using namespace Pgsql;
|
||||
|
||||
QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
QString name;
|
||||
auto auth_ids = cat.authIds();
|
||||
if (auth_ids) {
|
||||
const PgAuthId* auth_id = auth_ids->getByKey(oid);
|
||||
if (auth_id) {
|
||||
name = auth_id->name;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
QString name = getRoleNameFromOid(cat, oid);
|
||||
return name;
|
||||
}
|
||||
|
||||
QString getClassDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
QString result;
|
||||
auto l = cat.classes();
|
||||
auto e = l->getByKey(oid);
|
||||
if (e)
|
||||
result = e->objectName();
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
QString getIndexDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
QString result;
|
||||
// auto l = cat.indexes();
|
||||
// auto e = l->getByKey(oid);
|
||||
// if (e)
|
||||
result = getClassDisplayString(cat, oid);
|
||||
return result;
|
||||
}
|
||||
|
||||
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
// TODO load list and lookup name
|
||||
if (oid == 0) {
|
||||
auto dbname = cat.getDBName();
|
||||
oid = cat.databases()->getByName(dbname)->tablespace;
|
||||
auto ts = cat.tablespaces()->getByKey(oid);
|
||||
return ts->name + " (inherited)";
|
||||
}
|
||||
else {
|
||||
auto ts = cat.tablespaces()->getByKey(oid);
|
||||
return ts->name;
|
||||
}
|
||||
}
|
||||
|
||||
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod)
|
||||
{
|
||||
if (oid == 0) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
auto tc = cat.types();
|
||||
auto t = tc->getByKey(oid);
|
||||
if (t == nullptr) {
|
||||
return "(invalid/unknown)";
|
||||
}
|
||||
QString s;
|
||||
if (t->category == TypCategory::Array) {
|
||||
// auto et = tc->getByKey(t.elem);
|
||||
// s = et.name;
|
||||
s = getTypeDisplayString(cat, t->elem, typmod);
|
||||
s += "[]";
|
||||
}
|
||||
else {
|
||||
s = t->objectName();
|
||||
switch (oid) {
|
||||
case varchar_oid:
|
||||
case char_oid:
|
||||
case text_oid:
|
||||
if (typmod > 4)
|
||||
s += QString::asprintf("(%d)", typmod-4);
|
||||
break;
|
||||
case numeric_oid:
|
||||
if (typmod > 4) {
|
||||
int prec = (typmod - 4) / 65536;
|
||||
int scale = (typmod - 4) % 65536;
|
||||
if (scale > 0)
|
||||
s += QString::asprintf("(%d,%d)", prec, scale);
|
||||
else
|
||||
s += QString::asprintf("(%d)", prec);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PgDatabaseCatalog::PgDatabaseCatalog()
|
||||
{
|
||||
}
|
||||
|
||||
PgDatabaseCatalog::~PgDatabaseCatalog()
|
||||
{
|
||||
}
|
||||
|
||||
void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn,
|
||||
std::function<bool(int, int)> progress_callback)
|
||||
{
|
||||
loadInfo(conn);
|
||||
const int count = 12;
|
||||
int n = 0;
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
|
||||
// First load server objects
|
||||
load2(m_authIds, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_tablespaces, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_databases, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
|
||||
// Load database objects
|
||||
load2(m_namespaces, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_collations, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_classes, conn); // needs namespaces
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_attributes, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_constraints, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_indexes, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_ams, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_triggers, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_types, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_procs, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_inherits, conn);
|
||||
progress_callback && progress_callback(++n, count);
|
||||
|
||||
refreshed(this, All);
|
||||
}
|
||||
|
||||
void PgDatabaseCatalog::loadInfo(Pgsql::Connection &conn)
|
||||
{
|
||||
Pgsql::Result r = conn.query("SHOW server_version_num");
|
||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||
if (r.rows() == 1)
|
||||
m_serverVersion << r.get(0, 0);
|
||||
|
||||
r = conn.query("SELECT version()");
|
||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||
if (r.rows() == 1)
|
||||
m_serverVersionString = r.get(0, 0).asQString();
|
||||
|
||||
m_dbName = conn.getDBName();
|
||||
}
|
||||
|
||||
void load(Pgsql::Connection &conn, IPgContainer &pg_cont)
|
||||
{
|
||||
//QThread::msleep(400);
|
||||
std::string q = pg_cont.getLoadQuery();
|
||||
Pgsql::Result result = conn.query(q.c_str());
|
||||
if (result && result.resultStatus() == PGRES_TUPLES_OK) {
|
||||
//boost::timer::auto_cpu_timer t;
|
||||
pg_cont.load(result);
|
||||
}
|
||||
else {
|
||||
auto details = result.diagDetails();
|
||||
if (details.state == "42501") { // permission denied
|
||||
// ignore this for now
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Query failed\n" + details.errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const QString& PgDatabaseCatalog::serverVersionString() const
|
||||
{
|
||||
return m_serverVersionString;
|
||||
}
|
||||
|
||||
int PgDatabaseCatalog::serverVersion() const
|
||||
{
|
||||
return m_serverVersion;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgAttributeContainer> PgDatabaseCatalog::attributes() const
|
||||
{
|
||||
return m_attributes;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgAuthIdContainer> PgDatabaseCatalog::authIds() const
|
||||
{
|
||||
return m_authIds;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgClassContainer> PgDatabaseCatalog::classes() const
|
||||
{
|
||||
return m_classes;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgConstraintContainer> PgDatabaseCatalog::constraints() const
|
||||
{
|
||||
return m_constraints;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgDatabaseContainer> PgDatabaseCatalog::databases() const
|
||||
{
|
||||
return m_databases;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgIndexContainer> PgDatabaseCatalog::indexes() const
|
||||
{
|
||||
return m_indexes;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgAmContainer> PgDatabaseCatalog::ams() const
|
||||
{
|
||||
return m_ams;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgNamespaceContainer> PgDatabaseCatalog::namespaces() const
|
||||
{
|
||||
return m_namespaces;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgTablespaceContainer> PgDatabaseCatalog::tablespaces() const
|
||||
{
|
||||
return m_tablespaces;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgTriggerContainer> PgDatabaseCatalog::triggers() const
|
||||
{
|
||||
return m_triggers;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgTypeContainer> PgDatabaseCatalog::types() const
|
||||
{
|
||||
return m_types;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgProcContainer> PgDatabaseCatalog::procs() const
|
||||
{
|
||||
return m_procs;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgCollationContainer> PgDatabaseCatalog::collations() const
|
||||
{
|
||||
return m_collations;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgInheritsContainer> PgDatabaseCatalog::inherits() const
|
||||
{
|
||||
return m_inherits;
|
||||
}
|
||||
124
pglablib/catalog/PgDatabaseCatalog.h
Normal file
124
pglablib/catalog/PgDatabaseCatalog.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
#ifndef PGSQLDATABASECATALOGUE_H
|
||||
#define PGSQLDATABASECATALOGUE_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Connection;
|
||||
|
||||
}
|
||||
|
||||
class PgAttributeContainer;
|
||||
class PgAuthIdContainer;
|
||||
class PgClassContainer;
|
||||
class PgConstraintContainer;
|
||||
class PgDatabaseContainer;
|
||||
class PgIndexContainer;
|
||||
class PgNamespaceContainer;
|
||||
class PgAmContainer;
|
||||
class PgTablespaceContainer;
|
||||
class PgTriggerContainer;
|
||||
class PgTypeContainer;
|
||||
class PgProcContainer;
|
||||
class PgCollationContainer;
|
||||
class PgInheritsContainer;
|
||||
|
||||
|
||||
class PgDatabaseCatalog: public QObject, public std::enable_shared_from_this<PgDatabaseCatalog> {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PgDatabaseCatalog();
|
||||
PgDatabaseCatalog(const PgDatabaseCatalog&) = delete;
|
||||
PgDatabaseCatalog& operator = (const PgDatabaseCatalog&) = delete;
|
||||
~PgDatabaseCatalog();
|
||||
|
||||
void loadAll(Pgsql::Connection &conn,
|
||||
std::function<bool(int, int)> progress_callback);
|
||||
|
||||
void loadInfo(Pgsql::Connection &conn);
|
||||
|
||||
const QString& serverVersionString() const;
|
||||
int serverVersion() const;
|
||||
const QString& getDBName() const { return m_dbName; }
|
||||
|
||||
std::shared_ptr<const PgAttributeContainer> attributes() const;
|
||||
std::shared_ptr<const PgAuthIdContainer> authIds() const;
|
||||
std::shared_ptr<const PgClassContainer> classes() const;
|
||||
std::shared_ptr<const PgConstraintContainer> constraints() const;
|
||||
std::shared_ptr<const PgDatabaseContainer> databases() const;
|
||||
std::shared_ptr<const PgIndexContainer> indexes() const;
|
||||
std::shared_ptr<const PgAmContainer> ams() const;
|
||||
std::shared_ptr<const PgNamespaceContainer> namespaces() const;
|
||||
std::shared_ptr<const PgTablespaceContainer> tablespaces() const;
|
||||
std::shared_ptr<const PgTriggerContainer> triggers() const;
|
||||
std::shared_ptr<const PgTypeContainer> types() const;
|
||||
std::shared_ptr<const PgProcContainer> procs() const;
|
||||
std::shared_ptr<const PgCollationContainer> collations() const;
|
||||
std::shared_ptr<const PgInheritsContainer> inherits() const;
|
||||
|
||||
enum RefreshFlag {
|
||||
Attributes = 1,
|
||||
AuthIds = (1 << 1),
|
||||
Classes = (1 << 2),
|
||||
Constraints = (1 << 3),
|
||||
Databases = (1 << 4),
|
||||
Indexes = (1 << 5),
|
||||
Ams = (1 << 6),
|
||||
Namespaces = (1 << 7),
|
||||
Tablespaces = (1 << 8),
|
||||
Triggers = (1 << 9),
|
||||
Types = (1 << 10),
|
||||
Proc = (1 << 11),
|
||||
All = 0xffffffff
|
||||
};
|
||||
using RefreshFlags = int;
|
||||
|
||||
signals:
|
||||
void refreshed(const PgDatabaseCatalog *catalog, RefreshFlags flags);
|
||||
private:
|
||||
QString m_serverVersionString;
|
||||
int m_serverVersion;
|
||||
QString m_dbName;
|
||||
|
||||
std::shared_ptr<PgAttributeContainer> m_attributes;
|
||||
std::shared_ptr<PgAuthIdContainer> m_authIds;
|
||||
std::shared_ptr<PgClassContainer> m_classes;
|
||||
std::shared_ptr<PgConstraintContainer> m_constraints;
|
||||
std::shared_ptr<PgDatabaseContainer> m_databases;
|
||||
std::shared_ptr<PgIndexContainer> m_indexes;
|
||||
std::shared_ptr<PgAmContainer> m_ams;
|
||||
std::shared_ptr<PgNamespaceContainer> m_namespaces;
|
||||
std::shared_ptr<PgTablespaceContainer> m_tablespaces;
|
||||
std::shared_ptr<PgTriggerContainer> m_triggers;
|
||||
std::shared_ptr<PgTypeContainer> m_types;
|
||||
std::shared_ptr<PgProcContainer> m_procs;
|
||||
std::shared_ptr<PgCollationContainer> m_collations;
|
||||
std::shared_ptr<PgInheritsContainer> m_inherits;
|
||||
|
||||
template <typename T>
|
||||
void load2(std::shared_ptr<T> &ptr, Pgsql::Connection &conn)
|
||||
{
|
||||
if (!ptr)
|
||||
ptr = std::make_shared<T>(*this);
|
||||
|
||||
load(conn, *ptr);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod = -1);
|
||||
QString getIndexDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getClassDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||
|
||||
|
||||
#endif // PGSQLDATABASECATALOGUE_H
|
||||
21
pglablib/catalog/PgDatabaseContainer.cpp
Normal file
21
pglablib/catalog/PgDatabaseContainer.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include "PgDatabaseContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
std::string PgDatabaseContainer::getLoadQuery() const
|
||||
{
|
||||
return "SELECT oid,datname,datdba,encoding,datcollate,datctype,datistemplate,datallowconn,"
|
||||
"datconnlimit,dattablespace,datacl FROM pg_database";
|
||||
}
|
||||
|
||||
PgDatabase PgDatabaseContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
|
||||
Oid oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
PgDatabase v(m_catalog, oid, name);
|
||||
col >> v.dba >> v.encoding >> v.collate >> v.ctype >> v.isTemplate
|
||||
>> v.allowConn >> v.connLimit >> v.tablespace >> v.acl;
|
||||
return v;
|
||||
}
|
||||
|
||||
26
pglablib/catalog/PgDatabaseContainer.h
Normal file
26
pglablib/catalog/PgDatabaseContainer.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef PGDATABASECONTAINER_H
|
||||
#define PGDATABASECONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgDatabase.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgDatabaseContainer: public PgContainer<PgDatabase> {
|
||||
public:
|
||||
//explicit PgDatabaseContainer(PgDatabaseCatalog *cat);
|
||||
using PgContainer<PgDatabase>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
PgDatabase loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGDATABASECONTAINER_H
|
||||
2
pglablib/catalog/PgDatabaseObject.cpp
Normal file
2
pglablib/catalog/PgDatabaseObject.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#include "PgDatabaseObject.h"
|
||||
|
||||
13
pglablib/catalog/PgDatabaseObject.h
Normal file
13
pglablib/catalog/PgDatabaseObject.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef PGDATABASEOBJECT_H
|
||||
#define PGDATABASEOBJECT_H
|
||||
|
||||
#include "PgServerObject.h"
|
||||
|
||||
/// Base class for objects that are part of a database
|
||||
class PgDatabaseObject: public PgServerObject {
|
||||
public:
|
||||
using PgServerObject::PgServerObject;
|
||||
|
||||
};
|
||||
|
||||
#endif // PGDATABASEOBJECT_H
|
||||
77
pglablib/catalog/PgIndex.cpp
Normal file
77
pglablib/catalog/PgIndex.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include "PgIndex.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgAmContainer.h"
|
||||
#include <QStringBuilder>
|
||||
|
||||
QString PgIndex::getAm() const
|
||||
{
|
||||
auto&& cat = catalog();
|
||||
QString result;
|
||||
auto idxcls = cat.classes()->getByKey(oid());
|
||||
if (idxcls) {
|
||||
auto am = cat.ams()->getByKey(idxcls->am);
|
||||
if (am)
|
||||
result = am->name; // objectName();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString PgIndex::createSql() const
|
||||
{
|
||||
return definition + ";";
|
||||
|
||||
// const PgClass *table_class = catalog.classes()->getByKey(index.relid);
|
||||
// const PgClass *index_class = catalog.classes()->getByKey(index.indexrelid);
|
||||
|
||||
// QString result;
|
||||
// result = "CREATE ";
|
||||
// if (index.isunique)
|
||||
// result += "UNIQUE ";
|
||||
// result += "INDEX "
|
||||
//// % quoteIdent(getIndexDisplayString(catalog, index.indexrelid))
|
||||
// % quoteIdent(index_class.name)
|
||||
// % "\n ON " % genFQTableName(catalog, table_class);
|
||||
//// % "\n USING " % index_class.am lookup in pg_am table
|
||||
// return result;
|
||||
|
||||
#if 0
|
||||
+ wxT("\n USING ") + GetIndexType()
|
||||
+ wxT("\n (");
|
||||
if (GetProcName().IsNull())
|
||||
str += GetQuotedColumns();
|
||||
else
|
||||
{
|
||||
str += GetQuotedSchemaPrefix(GetProcNamespace()) + qtIdent(GetProcName()) + wxT("(") + GetQuotedColumns() + wxT(")");
|
||||
if (!this->GetOperatorClasses().IsNull())
|
||||
str += wxT(" ") + GetOperatorClasses();
|
||||
}
|
||||
|
||||
str += wxT(")");
|
||||
|
||||
if (GetConnection()->BackendMinimumVersion(8, 2) && GetFillFactor().Length() > 0)
|
||||
str += wxT("\n WITH (FILLFACTOR=") + GetFillFactor() + wxT(")");
|
||||
|
||||
if (GetConnection()->BackendMinimumVersion(8, 0) && tablespace != GetDatabase()->GetDefaultTablespace())
|
||||
str += wxT("\nTABLESPACE ") + qtIdent(tablespace);
|
||||
|
||||
AppendIfFilled(str, wxT("\n WHERE "), GetConstraint());
|
||||
|
||||
str += wxT(";\n");
|
||||
|
||||
if (GetConnection()->BackendMinimumVersion(7, 5))
|
||||
if (GetIsClustered())
|
||||
str += wxT("ALTER TABLE ") + GetQuotedSchemaPrefix(GetIdxSchema()) + qtIdent(GetIdxTable())
|
||||
+ wxT(" CLUSTER ON ") + qtIdent(GetName())
|
||||
+ wxT(";\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
QString PgIndex::dropSql() const
|
||||
{
|
||||
QString result;
|
||||
result = "DROP INDEX "
|
||||
% fullyQualifiedQuotedObjectName()
|
||||
% ";";
|
||||
return result;
|
||||
}
|
||||
45
pglablib/catalog/PgIndex.h
Normal file
45
pglablib/catalog/PgIndex.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef PGINDEX_H
|
||||
#define PGINDEX_H
|
||||
|
||||
#include "PgNamespaceObject.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
class PgIndex : public PgNamespaceObject {
|
||||
public:
|
||||
|
||||
// Oid indexrelid = InvalidOid; // oid of pg_class for this index
|
||||
Oid relid = InvalidOid; // oid of table (pg_class) where this is an index on
|
||||
int16_t natts = 0;
|
||||
bool isunique = false;
|
||||
bool isprimary = false;
|
||||
bool isexclusion = false;
|
||||
bool immediate = false;
|
||||
bool isclustered = false;
|
||||
bool isvalid = false;
|
||||
bool checkxmin = false;
|
||||
bool isready = false;
|
||||
bool islive = false;
|
||||
bool isreplident = false;
|
||||
std::vector<int16_t> key;
|
||||
std::vector<Oid> collation;
|
||||
std::vector<Oid> indclass;
|
||||
std::vector<int16_t> option;
|
||||
QString exprs;
|
||||
QString pred;
|
||||
QString definition;
|
||||
|
||||
using PgNamespaceObject::PgNamespaceObject;
|
||||
QString getAm() const;
|
||||
|
||||
// bool operator==(Oid _oid) const { return indexrelid == _oid; }
|
||||
// //bool operator==(const QString &n) const { return name == n; }
|
||||
// bool operator<(Oid _oid) const { return indexrelid < _oid; }
|
||||
// bool operator<(const PgIndex &rhs) const { return indexrelid < rhs.indexrelid; }
|
||||
|
||||
QString createSql() const;
|
||||
QString dropSql() const;
|
||||
};
|
||||
|
||||
#endif // PGINDEX_H
|
||||
53
pglablib/catalog/PgIndexContainer.cpp
Normal file
53
pglablib/catalog/PgIndexContainer.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#include "PgIndexContainer.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include <iterator>
|
||||
|
||||
std::string PgIndexContainer::getLoadQuery() const
|
||||
{
|
||||
std::string q = R"__(
|
||||
SELECT indexrelid, indrelid, indnatts, indisunique, indisprimary,
|
||||
indisexclusion, indimmediate, indisclustered, indisvalid,
|
||||
indcheckxmin, indisready, indislive, indkey,
|
||||
indcollation, indclass, indoption, indexprs, indpred,
|
||||
pg_get_indexdef(indexrelid))__";
|
||||
|
||||
if (minimumVersion(90400))
|
||||
q += ", indisreplident ";
|
||||
q += "\nFROM pg_index";
|
||||
return q;
|
||||
}
|
||||
|
||||
PgIndex PgIndexContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
Oid indexrelid = col.nextValue();
|
||||
auto&& cls = m_catalog.classes()->getByKey(indexrelid);
|
||||
auto&& name = cls->objectName();
|
||||
auto&& nsoid = cls->nsOid();
|
||||
|
||||
PgIndex v(m_catalog, indexrelid, name, nsoid);
|
||||
col >> v.relid >> v.natts >> v.isunique
|
||||
>> v.isprimary >> v.isexclusion >> v.immediate >> v.isclustered
|
||||
>> v.isvalid >> v.checkxmin >> v.isready >> v.islive;
|
||||
col.getAsVector<int16_t>(std::back_inserter(v.key));
|
||||
col.getAsVector<Oid>(std::back_inserter(v.collation));
|
||||
col.getAsVector<Oid>(std::back_inserter(v.indclass));
|
||||
col.getAsVector<int16_t>(std::back_inserter(v.option));
|
||||
col >> v.exprs >> v.pred >> v.definition;
|
||||
if (minimumVersion(90400))
|
||||
col >> v.isreplident;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<PgIndex> PgIndexContainer::getIndexesForTable(Oid table_oid) const
|
||||
{
|
||||
std::vector<PgIndex> result;
|
||||
for (const auto &e : m_container)
|
||||
if (e.relid == table_oid)
|
||||
result.push_back(e);
|
||||
|
||||
return result;
|
||||
}
|
||||
19
pglablib/catalog/PgIndexContainer.h
Normal file
19
pglablib/catalog/PgIndexContainer.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef PGINDEXCONTAINER_H
|
||||
#define PGINDEXCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgIndex.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <vector>
|
||||
|
||||
class PgIndexContainer : public PgContainer<PgIndex> {
|
||||
public:
|
||||
using PgContainer<PgIndex>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
std::vector<PgIndex> getIndexesForTable(Oid table_oid) const;
|
||||
protected:
|
||||
virtual PgIndex loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
#endif // PGINDEXCONTAINER_H
|
||||
3
pglablib/catalog/PgInherits.cpp
Normal file
3
pglablib/catalog/PgInherits.cpp
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include "PgInherits.h"
|
||||
|
||||
PgInherits::PgInherits() = default;
|
||||
25
pglablib/catalog/PgInherits.h
Normal file
25
pglablib/catalog/PgInherits.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef PGINHERITS_H
|
||||
#define PGINHERITS_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
class PgInherits {
|
||||
public:
|
||||
using Key = std::tuple<Oid, int32_t>;
|
||||
|
||||
|
||||
Oid relid = InvalidOid; // oid
|
||||
Oid parent = InvalidOid; // oid
|
||||
int32_t seqno = 0; // integer
|
||||
|
||||
PgInherits();
|
||||
|
||||
bool operator==(Key _k) const { return relid == std::get<0>(_k) && seqno == std::get<1>(_k); }
|
||||
bool operator<(Key _k) const { return relid < std::get<0>(_k) || (relid == std::get<0>(_k) && seqno < std::get<1>(_k)); }
|
||||
bool operator<(const PgInherits &rhs) const { return relid < rhs.relid || (relid == rhs.relid && seqno < rhs.seqno); }
|
||||
};
|
||||
|
||||
#endif // PGINHERITS_H
|
||||
29
pglablib/catalog/PgInheritsContainer.cpp
Normal file
29
pglablib/catalog/PgInheritsContainer.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include "PgInheritsContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include <algorithm>
|
||||
|
||||
std::vector<Oid> PgInheritsContainer::getParentsOf(Oid oid) const
|
||||
{
|
||||
std::vector<Oid> result;
|
||||
auto&& iter = std::lower_bound(m_container.begin(), m_container.end(), PgInherits::Key{ oid, 1 });
|
||||
for (;iter != m_container.end() && iter->relid == oid; ++iter)
|
||||
result.push_back(iter->parent);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string PgInheritsContainer::getLoadQuery() const
|
||||
{
|
||||
return
|
||||
"SELECT inhrelid, inhparent, inhseqno \n"
|
||||
" FROM pg_inherits";
|
||||
}
|
||||
|
||||
|
||||
PgInherits PgInheritsContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgInherits v;
|
||||
col >> v.relid >> v.parent >> v.seqno;
|
||||
return v;
|
||||
}
|
||||
22
pglablib/catalog/PgInheritsContainer.h
Normal file
22
pglablib/catalog/PgInheritsContainer.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef PGINHERITSCONTAINER_H
|
||||
#define PGINHERITSCONTAINER_H
|
||||
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgInherits.h"
|
||||
#include "Pgsql_declare.h"
|
||||
|
||||
|
||||
class PgInheritsContainer : public PgContainer<PgInherits, PgInherits::Key> {
|
||||
public:
|
||||
using PgContainer<PgInherits, PgInherits::Key>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
|
||||
/// Returns the parents in the correct order
|
||||
std::vector<Oid> getParentsOf(Oid oid) const;
|
||||
protected:
|
||||
PgInherits loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
#endif // PGINHERITSCONTAINER_H
|
||||
116
pglablib/catalog/PgKeywordList.cpp
Normal file
116
pglablib/catalog/PgKeywordList.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "PgKeywordList.h"
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
using KeywordHT = boost::container::flat_set<Keyword>;
|
||||
|
||||
#define PG_KEYWORD(a,b,c) {a,c},
|
||||
const KeywordHT _ScanKeywords = {
|
||||
#include <server/parser/kwlist.h>
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const Keyword* getPgsqlKeyword(QString s)
|
||||
{
|
||||
const Keyword *result = nullptr;
|
||||
auto fr = _ScanKeywords.find(Keyword(s.toLower(), 0));
|
||||
if (fr != _ScanKeywords.end())
|
||||
result = &*fr;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//t_SymbolSet g_Keywords = {
|
||||
// "a", "abort", "abs", "absent", "absolute", "access", "according", "action", "ada", "add",
|
||||
// "admin", "after", "aggregate", "all", "allocate", "also", "alter", "analyse", "analyze", "and",
|
||||
// "any", "are", "array", "array_agg", "array_max_cardinality", "as", "asc", "asensitive",
|
||||
// "assetion", "assignment", "asymmetric", "at", "atomic", "attribute", "attributes", "authorization", "avg",
|
||||
// "backward", "base64", "before", "begin", "begin_frame", "begin_partition", "bernoulli", "between", "bigint", "binary",
|
||||
// "bit", "bit_length", "blob", "blocked", "bom", "boolean", "both", "breadth", "buffer", "by",
|
||||
// "c", "cache", "call", "called", "cardinality", "cascade", "cascaded", "case", "cast",
|
||||
// "catalog", "catalog_name", "ceil", "ceiling", "chain", "char", "character", "characteristics",
|
||||
// "characters", "character_length", "character_set_catalog", "character_set_name", "character_set_schema",
|
||||
// "char_length", "check", "checkpoint", "class", "class_origin", "clob", "close", "cluster",
|
||||
// "coalesce", "cobol", "collate", "collation", "collation_catalog", "collation_name", "collation_schema",
|
||||
// "collect", "column", "columns", "column_name", "command_function", "command_function_code",
|
||||
// "comment", "comments", "commit", "committed", "concurrently", "condition", "condition_number",
|
||||
// "configuration", "conflict", "connect", "connection", "connection_name", "constraint", "constraints",
|
||||
// "constraint_catalog", "constraint_name", "constraint_schema", "constructor", "contains", "content",
|
||||
// "continue", "control", "conversion", "convert", "copy", "corr", "corresponding", "cost", "count",
|
||||
// "covar_pop", "covar_samp", "create", "cross", "csv", "cube", "cume_dist", "current", "current_catalog",
|
||||
// "current_date", "current_default_transform_group", "current_path", "current_role", "current_row",
|
||||
// "current_schema", "current_time", "current_timestamp", "current_transform_group_for_type",
|
||||
// "current_user", "cursor", "cursor_name", "cycle",
|
||||
// "data", "database", "datalink", "date", "datetime_interval_code", "datetime_interval_precision",
|
||||
// "day", "db", "deallocate", "dec", "decimal", "declare", "default", "defaults", "deferrable", "deferred",
|
||||
// "defined", "definer", "degree", "delete", "delimiter", "delimiters", "dense_rank", "depends", "depth",
|
||||
// "deref", "derived", "desc", "describe", "descriptor", "deterministic", "diagnostics", "dictionary",
|
||||
// "disable", "discard", "disconnect", "dispatch", "distinct", "dlnewcopy", "dlpreviouscopy", "dlurlcomplete",
|
||||
// "dlurlcompleteonly", "dlurlcompletewrite", "dlurlpatch", "dlurlpathonly", "dlurlpathwrite", "dlurlscheme",
|
||||
// "dlurlserver", "dlvalue", "do", "document", "domain", "double", "drop", "dynamic", "dynamic_function",
|
||||
// "dynamic_function_code",
|
||||
// "each", "element", "else", "empty", "enable", "encodign", "encrypted", "end", "end-exec", "end_frame",
|
||||
// "end_partition", "enforced", "enum", "equals", "escape", "event", "every", "except", "exception", "exclude",
|
||||
// "excluding", "exclusive", "exec", "execute", "exists", "exp", "explain", "expression", "extenstion",
|
||||
// "external", "extract", "false", "family", "fetch", "file", "filter", "final", "first", "first_value",
|
||||
// "flag", "float", "floor", "following", "for", "force", "foreign", "fortran", "forward", "found",
|
||||
// "frame_row", "free", "freeze", "from", "fs", "full", "function", "functions", "fusion",
|
||||
// "g", "general", "generated", "get", "global", "go" "goto", "grant", "granted", "greatest", "group",
|
||||
// "grouping", "groups", "handler", "having", "header", "hex", "hierarchy", "hold", "hour", "id", "identity",
|
||||
// "if", "ignore", "ilike", "immediate", "immediatly", "immutable", "implementation", "implicit", "import", "in",
|
||||
// "including", "increment", "indent", "index", "indexes", "indicator", "inherit", "inherits", "initially", "inline",
|
||||
// "inner", "inout", "input", "insensitive", "insert", "instance", "instantiable", "instead", "int", "integer",
|
||||
// "integrity", "intersect", "intersection", "interval", "into", "invoker", "is", "isnull", "isolation",
|
||||
// "join",
|
||||
// "k", "key", "key_member", "key_type",
|
||||
// "label", "lag", "language", "large", "last", "last_value", "lateral", "lead", "leading", "leakproof",
|
||||
// "least", "left", "length", "level", "library", "like", "like_regex", "limit", "link", "listen", "ln", "load", "local",
|
||||
// "localtime", "localtimestamp", "location", "locator", "lock", "locked", "logged", "lower",
|
||||
// "m", "map", "mapping", "match", "matched", "materialized", "max", "maxvalue", "max_cardinality", "member",
|
||||
// "merge", "message_length", "message_octet_length", "message_text", "method", "min", "minute", "minvalue",
|
||||
// "mod", "mode", "modifies", "module", "month", "more", "move", "multiset", "mumps",
|
||||
// "name", "namespace", "national", "natural", "nchar", "nclob", "nesting", "new", "next", "nfc", "nfd", "nfkc", "nkfd",
|
||||
// "nil", "no", "none", "normalize", "normalize", "not", "nothing", "notify", "notnull", "nowait", "nth_value", "ntile",
|
||||
// "null", "nullable", "nullif", "nulls", "number", "numeric",
|
||||
// "object", "occurrences_regex", "octets", "octet_length", "of", "off", "offset", "oids", "old", "on", "only", "open",
|
||||
// "operator", "option", "options", "or", "order", "ordering", "ordinality", "others", "out", "outer", "output", "over",
|
||||
// "overlaps", "overlay", "overriding", "owned", "owner",
|
||||
// "p", "pad", "parallel", "parameter", "parameter_mode", "parameter_name", "parameter_specific_catalog",
|
||||
// "parameter_specific_name", "parameter_specific_schema", "parser",
|
||||
// "partial", "partition", "pascal", "passing", "passthrough", "password", "path", "percent", "percentile_cont",
|
||||
// "percentile_disc", "percent_rank", "period", "permission", "placing", "plans", "pli", "policy", "portion",
|
||||
// "position", "position_regex", "power", "precedes", "preceding", "precision", "prepare", "prepared", "preserve",
|
||||
// "primary", "prior", "privileges", "procedural", "procedure", "program", "public",
|
||||
// "quote", "range", "rank", "read", "reads", "real", "reassign", "recheck", "recovery", "recursive", "ref",
|
||||
// "references", "referencing", "refresh", "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2",
|
||||
// "regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "reindex", "relative", "release", "rename", "repeatable",
|
||||
// "replace", "replica", "requiring", "reset", "respect", "restart", "restore", "restrict", "result", "return",
|
||||
// "returned_cardinality", "returned_length", "returned_octet_length", "returned_sqlstate", "returning", "returns",
|
||||
// "revoke", "right", "role", "rollback", "rollup", "routine", "routine_catalog", "routine_name", "routine_schema",
|
||||
// "row", "rows", "row_count", "row_number", "rule",
|
||||
// "savepoint", "scale", "schema", "schema_name", "scope", "scope_catalog", "scope_name", "scope_schema", "scroll",
|
||||
// "search", "second", "section", "security", "select", "selective", "self", "sensitive", "sequence", "sequences",
|
||||
// "serializable", "server", "server_name", "session", "session_user", "set", "setof", "sets", "share", "show",
|
||||
// "similar", "simple", "size", "skip", "smallint", "snapshot", "some", "source", "space", "specific", "specifictype",
|
||||
// "specific_name", "sql", "sqlcode", "sqlerror", "sqlexception", "sqlstate", "sqlwarning", "sqrt", "stable",
|
||||
// "standalone", "start", "state", "statement", "static", "statistics", "stddev_pop", "stddev_samp", "stdin", "stdout",
|
||||
// "storage", "strict", "strip", "structure", "style", "subclass_origin", "submultiset", "substring", "substring_regex",
|
||||
// "succeeds", "sum", "symmetric", "sysid", "system", "system_time", "system_user",
|
||||
// "t", "table", "tables", "tablesample", "tablespace", "table_name", "temp", "template", "temporary", "text", "then",
|
||||
// "ties", "time", "timestamp", "timezone_hour", "timezone_minute", "to", "token", "top_level_count", "trailing",
|
||||
// "transaction", "transaction_committed", "transaction_rolled_back", "transaction_active", "transform", "transforms",
|
||||
// "translate", "translate_regex", "translation", "treat", "trigger", "trigger_catalog", "trigger_name", "trigger_schema",
|
||||
// "trim", "trim_array", "true", "truncate", "trusted", "type", "types", "uescape", "unbounded", "uncommitted", "under",
|
||||
// "unencrypted", "union", "unique", "unknown", "unlink", "unlisten", "unlogged", "unnamed", "unnest", "until", "untyped",
|
||||
// "update", "upper", "uri", "usage", "user", "user_defined_type_catalog", "user_defined_type_code",
|
||||
// "user_defined_type_name", "user_defined_type_schema", "using",
|
||||
// "vacuum", "valid", "validate", "validator", "value", "values", "value_of", "varbinary", "varchar", "variadic",
|
||||
// "varying", "var_pop", "var_samp", "verbose", "version", "versioning", "view", "views", "volatile",
|
||||
// "when", "whenever", "where", "whitespace", "width_bucket", "window", "with", "within", "without", "work", "wrapper",
|
||||
// "write", "xml", "xmlagg", "xmlattributes", "xmlbinary", "xmlcast", "xmlcomment", "xmlconcat", "xmldeclaration",
|
||||
// "xmldocument", "xmlelement", "xmlexists", "xmlforest", "xmliterate", "xmlnamespaces", "xmlparse", "xmlpi",
|
||||
// "xmlquery", "xmlroot", "xmlschema", "xmlserialize", "xmltable", "xmltext", "xmlvalidate", "year", "yes", "zone"
|
||||
//};
|
||||
|
||||
51
pglablib/catalog/PgKeywordList.h
Normal file
51
pglablib/catalog/PgKeywordList.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef PGKEYWORDLIST_H
|
||||
#define PGKEYWORDLIST_H
|
||||
|
||||
#include <QString>
|
||||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include "util.h"
|
||||
|
||||
#define UNRESERVED_KEYWORD 0
|
||||
#define COL_NAME_KEYWORD 1
|
||||
#define TYPE_FUNC_NAME_KEYWORD 2
|
||||
#define RESERVED_KEYWORD 3
|
||||
|
||||
|
||||
|
||||
using t_SymbolSet = std::unordered_set<QString>;
|
||||
|
||||
|
||||
class Keyword {
|
||||
public:
|
||||
Keyword(QString kw, int16_t cat)
|
||||
: m_keyword(kw), m_category(cat)
|
||||
{}
|
||||
|
||||
const QString& getKeyword() const { return m_keyword; }
|
||||
int16_t getCategory() const { return m_category; }
|
||||
|
||||
//bool operator<(const QString &s) const { return m_keyword < s; }
|
||||
bool operator<(const Keyword &kw) const { return m_keyword < kw.m_keyword; }
|
||||
private:
|
||||
QString m_keyword;
|
||||
int16_t m_category;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<Keyword>
|
||||
{
|
||||
std::size_t operator()(const Keyword& s) const
|
||||
{
|
||||
return qHash(s.getKeyword());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const Keyword* getPgsqlKeyword(QString s);
|
||||
|
||||
|
||||
#endif // PGKEYWORDLIST_H
|
||||
8
pglablib/catalog/PgNamespace.cpp
Normal file
8
pglablib/catalog/PgNamespace.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include "PgNamespace.h"
|
||||
|
||||
bool PgNamespace::isSystemCatalog() const
|
||||
{
|
||||
auto&& n = objectName();
|
||||
return n.startsWith("pg_")
|
||||
|| n == "information_schema";
|
||||
}
|
||||
28
pglablib/catalog/PgNamespace.h
Normal file
28
pglablib/catalog/PgNamespace.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef PGNAMESPACE_H
|
||||
#define PGNAMESPACE_H
|
||||
|
||||
#include "PgDatabaseObject.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
|
||||
/// Object representing a namespace within a database
|
||||
class PgNamespace: public PgDatabaseObject {
|
||||
public:
|
||||
|
||||
// Oid oid = InvalidOid;
|
||||
// QString name;
|
||||
Oid owner = InvalidOid;
|
||||
QString acl;
|
||||
|
||||
using PgDatabaseObject::PgDatabaseObject;
|
||||
|
||||
// bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
// bool operator==(const QString &n) const { return objectName() == n; }
|
||||
// bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
// bool operator<(const PgNamespace &rhs) const { return oid < rhs.oid; }
|
||||
|
||||
bool isSystemCatalog() const;
|
||||
};
|
||||
|
||||
#endif // PGNAMESPACE_H
|
||||
21
pglablib/catalog/PgNamespaceContainer.cpp
Normal file
21
pglablib/catalog/PgNamespaceContainer.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include "PgNamespaceContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "Pgsql_Result.h"
|
||||
#include "Pgsql_Value.h"
|
||||
|
||||
std::string PgNamespaceContainer::getLoadQuery() const
|
||||
{
|
||||
return "SELECT oid, nspname, nspowner, nspacl FROM pg_catalog.pg_namespace";
|
||||
}
|
||||
|
||||
PgNamespace PgNamespaceContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
|
||||
Oid oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
PgNamespace v(m_catalog, oid, name);
|
||||
col >> v.owner >> v.acl;
|
||||
return v;
|
||||
}
|
||||
|
||||
24
pglablib/catalog/PgNamespaceContainer.h
Normal file
24
pglablib/catalog/PgNamespaceContainer.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef PGNAMESPACECONTAINER_H
|
||||
#define PGNAMESPACECONTAINER_H
|
||||
|
||||
#include "PgNamespace.h"
|
||||
#include "PgContainer.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
class PgNamespaceContainer: public PgContainer<PgNamespace> {
|
||||
public:
|
||||
using PgContainer<PgNamespace>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
virtual PgNamespace loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGNAMESPACECONTAINER_H
|
||||
40
pglablib/catalog/PgNamespaceObject.cpp
Normal file
40
pglablib/catalog/PgNamespaceObject.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include "PgNamespaceObject.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgNamespace.h"
|
||||
#include "PgNamespaceContainer.h"
|
||||
#include "SqlFormattingUtils.h"
|
||||
|
||||
PgNamespaceObject::PgNamespaceObject(PgDatabaseCatalog& cat, Oid oid, const QString &name, Oid schema_oid)
|
||||
: PgDatabaseObject(cat, oid, name)
|
||||
, m_schemaOid(schema_oid)
|
||||
{}
|
||||
|
||||
Oid PgNamespaceObject::nsOid() const
|
||||
{
|
||||
return m_schemaOid;
|
||||
}
|
||||
|
||||
//void PgSchemaObject::setSchemaOid(Oid oid)
|
||||
//{
|
||||
// m_schemaOid = oid;
|
||||
//}
|
||||
|
||||
QString PgNamespaceObject::nsName() const
|
||||
{
|
||||
return ns().objectName();
|
||||
}
|
||||
|
||||
QString PgNamespaceObject::quotedNsName() const
|
||||
{
|
||||
return quoteIdent(nsName());
|
||||
}
|
||||
|
||||
QString PgNamespaceObject::fullyQualifiedQuotedObjectName() const
|
||||
{
|
||||
return quotedNsName() + "." + quotedObjectName();
|
||||
}
|
||||
|
||||
const PgNamespace& PgNamespaceObject::ns() const
|
||||
{
|
||||
return *catalog().namespaces()->getByKey(m_schemaOid);
|
||||
}
|
||||
28
pglablib/catalog/PgNamespaceObject.h
Normal file
28
pglablib/catalog/PgNamespaceObject.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef PGSCHEMAOBJECT_H
|
||||
#define PGSCHEMAOBJECT_H
|
||||
|
||||
#include <QString>
|
||||
#include "PgDatabaseObject.h"
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgNamespace;
|
||||
|
||||
/// Base class for database objects that are part of a specific schema
|
||||
class PgNamespaceObject: public PgDatabaseObject {
|
||||
public:
|
||||
|
||||
PgNamespaceObject(PgDatabaseCatalog& cat, Oid oid, const QString &name, Oid schema_oid);
|
||||
|
||||
Oid nsOid() const;
|
||||
// void setSchemaOid(Oid oid);
|
||||
QString nsName() const;
|
||||
QString quotedNsName() const;
|
||||
/// Returns the schema name and object name with proper quotes
|
||||
QString fullyQualifiedQuotedObjectName() const;
|
||||
|
||||
const PgNamespace& ns() const;
|
||||
private:
|
||||
Oid m_schemaOid = InvalidOid;
|
||||
};
|
||||
|
||||
#endif // PGSCHEMAOBJECT_H
|
||||
36
pglablib/catalog/PgObject.cpp
Normal file
36
pglablib/catalog/PgObject.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "PgObject.h"
|
||||
#include "SqlFormattingUtils.h"
|
||||
|
||||
PgObject::PgObject(PgDatabaseCatalog& cat, Oid oid, const QString &name)
|
||||
: m_catalog(&cat)
|
||||
, m_oid(oid)
|
||||
, m_name(name)
|
||||
{}
|
||||
|
||||
PgObject::~PgObject()
|
||||
{}
|
||||
|
||||
Oid PgObject::oid() const
|
||||
{
|
||||
return m_oid;
|
||||
}
|
||||
|
||||
const QString& PgObject::objectName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QString PgObject::quotedObjectName() const
|
||||
{
|
||||
return quoteIdent(objectName());
|
||||
}
|
||||
|
||||
const PgDatabaseCatalog& PgObject::catalog() const
|
||||
{
|
||||
return *m_catalog;
|
||||
}
|
||||
|
||||
void test(PgObject a, PgObject b)
|
||||
{
|
||||
a = b;
|
||||
}
|
||||
32
pglablib/catalog/PgObject.h
Normal file
32
pglablib/catalog/PgObject.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef PGOBJECT_H
|
||||
#define PGOBJECT_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <QString>
|
||||
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class PgObject {
|
||||
public:
|
||||
explicit PgObject(PgDatabaseCatalog& cat, Oid oid, const QString &name);
|
||||
virtual ~PgObject();
|
||||
|
||||
Oid oid() const;
|
||||
const QString& objectName() const;
|
||||
/// Default implementation uses objectName and add quotes when needed.
|
||||
virtual QString quotedObjectName() const;
|
||||
|
||||
bool operator==(Oid _oid) const { return m_oid == _oid; }
|
||||
bool operator==(const QString &n) const { return m_name == n; }
|
||||
bool operator<(Oid _oid) const { return m_oid < _oid; }
|
||||
bool operator<(const PgObject &rhs) const { return m_oid < rhs.m_oid; }
|
||||
protected:
|
||||
const PgDatabaseCatalog& catalog() const;
|
||||
|
||||
private:
|
||||
PgDatabaseCatalog* m_catalog;
|
||||
Oid m_oid;
|
||||
QString m_name;
|
||||
};
|
||||
|
||||
#endif // PGOBJECT_H
|
||||
25
pglablib/catalog/PgOwnedObject.cpp
Normal file
25
pglablib/catalog/PgOwnedObject.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#include "PgOwnedObject.h"
|
||||
#include "PgAuthId.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
|
||||
void PgOwnedObject::setOwnerOid(PgDatabaseCatalog& cat, Oid oid)
|
||||
{
|
||||
m_ownerOid = oid;
|
||||
m_owner = cat.authIds()->getByKey(oid);
|
||||
}
|
||||
|
||||
Oid PgOwnedObject::ownerOid() const
|
||||
{
|
||||
return m_ownerOid;
|
||||
}
|
||||
|
||||
QString PgOwnedObject::ownerName() const
|
||||
{
|
||||
return m_owner->name;
|
||||
}
|
||||
|
||||
const PgAuthId* PgOwnedObject::owner() const
|
||||
{
|
||||
return m_owner;
|
||||
}
|
||||
22
pglablib/catalog/PgOwnedObject.h
Normal file
22
pglablib/catalog/PgOwnedObject.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef PGOWNEDOBJECT_H
|
||||
#define PGOWNEDOBJECT_H
|
||||
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include <memory>
|
||||
|
||||
class PgDatabaseCatalog;
|
||||
class PgAuthId;
|
||||
class PgOwnedObject {
|
||||
public:
|
||||
void setOwnerOid(PgDatabaseCatalog& cat, Oid oid);
|
||||
|
||||
Oid ownerOid() const;
|
||||
QString ownerName() const;
|
||||
const PgAuthId* owner() const;
|
||||
private:
|
||||
Oid m_ownerOid = InvalidOid;
|
||||
const PgAuthId * m_owner;
|
||||
};
|
||||
|
||||
#endif // PGOWNEDOBJECT_H
|
||||
278
pglablib/catalog/PgProc.cpp
Normal file
278
pglablib/catalog/PgProc.cpp
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
#include "PgProc.h"
|
||||
#include "std_utils.h"
|
||||
#include "SqlFormattingUtils.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
Arg::Mode CharToArgMode(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case 'i': return Arg::In;
|
||||
case 'o': return Arg::Out;
|
||||
case 'b': return Arg::InOut;
|
||||
case 'v': return Arg::Variadic;
|
||||
case 't': return Arg::Table;
|
||||
}
|
||||
throw std::runtime_error("Unexpected value for pg_proc.proargmodes");
|
||||
}
|
||||
|
||||
QString ArgModeToString(Arg::Mode m)
|
||||
{
|
||||
switch (m) {
|
||||
case Arg::In: return "IN";
|
||||
case Arg::Out: return "OUT";
|
||||
case Arg::InOut: return "INOUT";
|
||||
case Arg::Variadic: return "VARIADIC";
|
||||
case Arg::Table: return "TABLE";
|
||||
}
|
||||
throw std::runtime_error("Unexpected value for Arg::Mode");
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<QString> getArrayFromCommaSeparatedList(const QString &str)
|
||||
{
|
||||
std::vector<QString> res;
|
||||
const int len = str.length();
|
||||
if (len == 0)
|
||||
return res;
|
||||
|
||||
// setup start state for parsing
|
||||
int index = 0, brackets = 0, start_array = 0;
|
||||
bool single_quote = false, double_quote = false;
|
||||
|
||||
for(; index < len; index++) {
|
||||
QChar ch = str[index];
|
||||
if (!double_quote && ch == L'\'')
|
||||
single_quote = !single_quote;
|
||||
else if (!single_quote && ch == L'"')
|
||||
double_quote = !double_quote;
|
||||
else if (!double_quote && !single_quote && ch == L'(')
|
||||
brackets++;
|
||||
else if (!double_quote && !single_quote && ch == L')')
|
||||
brackets--;
|
||||
else if (!double_quote && !single_quote && brackets == 0 && ch == L',') {
|
||||
if (index != start_array)
|
||||
res.push_back(str.mid(start_array, index - 1).trimmed());
|
||||
else
|
||||
res.push_back(QString());
|
||||
start_array = index + 1;
|
||||
}
|
||||
}
|
||||
if (double_quote || single_quote || brackets != 0)
|
||||
throw std::runtime_error("Error parsing comma seperated array");
|
||||
|
||||
|
||||
// Add last value to array
|
||||
res.push_back(str.right(start_array).trimmed());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PgProc::setArgs(
|
||||
std::vector<Oid> argtypes,
|
||||
std::vector<Oid> allargtypes,
|
||||
std::vector<char> argmodes,
|
||||
std::vector<QString> argnames,
|
||||
std::optional<QString> argdefaults
|
||||
)
|
||||
{
|
||||
// When all args are of type IN allargtypes is empty and only argtypes is filled
|
||||
const std::vector<Oid> &types = allargtypes.empty() ? argtypes : allargtypes;
|
||||
const size_t count = types.size();
|
||||
m_args.clear();
|
||||
m_args.reserve(count);
|
||||
for (size_t index = 0; index < count; ++index) {
|
||||
// we "forget" the default here because it is easier
|
||||
// to apply them in reverse order when we have already
|
||||
// filled the list
|
||||
m_args.emplace_back(
|
||||
types[index],
|
||||
CharToArgMode(value_or(argmodes, index, 'i')),
|
||||
value_or(argnames, index, QString()),
|
||||
""
|
||||
);
|
||||
}
|
||||
auto defaults_array = getArrayFromCommaSeparatedList(argdefaults.value_or(QString()));
|
||||
|
||||
// Apply defaults from end to start to IN en INOUT parameters (others can't have a default)
|
||||
size_t arg_idx = m_args.size() - 1;
|
||||
for (auto def_iter = defaults_array.rbegin(); def_iter != defaults_array.rend(); ++def_iter) {
|
||||
// skip arguments with wrong mode
|
||||
while (m_args[arg_idx].mode != Arg::In && m_args[arg_idx].mode != Arg::InOut)
|
||||
if (arg_idx == 0) throw std::runtime_error("Error processing defaults");
|
||||
else --arg_idx;
|
||||
m_args[arg_idx].def = *def_iter;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Arg>& PgProc::args() const
|
||||
{
|
||||
return m_args;
|
||||
}
|
||||
|
||||
QString PgProc::argListWithNames(bool multiline) const
|
||||
{
|
||||
QString args;
|
||||
size_t nArgs = 0;
|
||||
|
||||
auto&& types = catalog().types();
|
||||
|
||||
for (auto&& arg_elem : m_args) {
|
||||
|
||||
// All Table arguments lies at the end of the list
|
||||
// Do not include them as the part of the argument list
|
||||
if (arg_elem.mode == Arg::Table)
|
||||
break;
|
||||
|
||||
nArgs++;
|
||||
if (args.length() > 0)
|
||||
args += (multiline) ? ",\n " : ", ";
|
||||
|
||||
QString arg;
|
||||
if (arg_elem.mode != Arg::In)
|
||||
arg += ArgModeToString(arg_elem.mode);
|
||||
|
||||
if (!arg_elem.name.isEmpty()) {
|
||||
if (!arg.isEmpty())
|
||||
arg += " ";
|
||||
arg += quoteIdent(arg_elem.name);
|
||||
}
|
||||
|
||||
if (!arg.isEmpty())
|
||||
arg += " ";
|
||||
arg += types->getByKey(arg_elem.type)->objectName();
|
||||
|
||||
if (!arg_elem.def.isEmpty())
|
||||
arg += " DEFAULT " + arg_elem.def;
|
||||
|
||||
args += arg;
|
||||
}
|
||||
|
||||
if (multiline && nArgs > 1)
|
||||
args = "\n " + args;
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
// Return the signature arguments list. If forScript = true, we format the list
|
||||
// appropriately for use in a SELECT script.
|
||||
QString PgProc::argSigList(const bool forScript) const
|
||||
{
|
||||
QString args;
|
||||
|
||||
auto&& types = catalog().types();
|
||||
|
||||
for (auto&& arg_elem : m_args) {
|
||||
// OUT parameters are not considered part of the signature, except for EDB-SPL,
|
||||
// although this is not true for EDB AS90 onwards..
|
||||
if (arg_elem.mode != Arg::Out && arg_elem.mode != Arg::Table) {
|
||||
if (args.length() > 0) {
|
||||
if (forScript)
|
||||
args += ",\n";
|
||||
else
|
||||
args += ", ";
|
||||
}
|
||||
|
||||
QString typname = types->getByKey(arg_elem.type)->objectName();
|
||||
if (forScript)
|
||||
args += " <" + typname + ">";
|
||||
else
|
||||
args += typname;
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
QString PgProc::createSql() const
|
||||
{
|
||||
if (createSqlCache.isEmpty()) {
|
||||
QString sql;
|
||||
|
||||
//wxString qtName = GetQuotedFullIdentifier() + wxT("(") + GetArgListWithNames(true) + wxT(")");
|
||||
QString quoted_name = QString("%1(%2)").arg(fullyQualifiedQuotedObjectName(), argListWithNames(true));
|
||||
// wxString qtSig = GetQuotedFullIdentifier() + wxT("(") + GetArgSigList() + wxT(")");
|
||||
QString quoted_sig = QString("%1(%2)").arg(fullyQualifiedQuotedObjectName(), argSigList());
|
||||
|
||||
auto&& types = catalog().types();
|
||||
QString return_type = types->getByKey(rettype)->objectName();
|
||||
|
||||
|
||||
sql = QString("-- Function: %1\n\n"
|
||||
"-- DROP FUNCTION %1;\n\n"
|
||||
"CREATE OR REPLACE FUNCTION %2\n"
|
||||
" RETURNS %3 AS\n"
|
||||
).arg(quoted_sig, quoted_name, return_type);
|
||||
|
||||
// if (GetLanguage().IsSameAs(wxT("C"), false))
|
||||
// {
|
||||
// sql += qtDbString(GetBin()) + wxT(", ") + qtDbString(GetSource());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (GetConnection()->BackendMinimumVersion(7, 5))
|
||||
// sql += qtDbStringDollar(GetSource());
|
||||
sql += dollarQuoteString(src);
|
||||
// else
|
||||
// sql += qtDbString(GetSource());
|
||||
// }
|
||||
// sql += wxT("\n LANGUAGE ") + GetLanguage() + wxT(" ");
|
||||
// if (GetConnection()->BackendMinimumVersion(8, 4) && GetIsWindow())
|
||||
// sql += wxT("WINDOW ");
|
||||
// sql += GetVolatility();
|
||||
|
||||
// if (GetConnection()->BackendMinimumVersion(9, 2) && GetIsLeakProof())
|
||||
// sql += wxT(" LEAKPROOF");
|
||||
// if (GetIsStrict())
|
||||
// sql += wxT(" STRICT");
|
||||
// if (GetSecureDefiner())
|
||||
// sql += wxT(" SECURITY DEFINER");
|
||||
|
||||
// // PostgreSQL 8.3+ cost/row estimations
|
||||
// if (GetConnection()->BackendMinimumVersion(8, 3))
|
||||
// {
|
||||
// sql += wxT("\n COST ") + NumToStr(GetCost());
|
||||
|
||||
// if (GetReturnAsSet())
|
||||
// sql += wxT("\n ROWS ") + NumToStr(GetRows());
|
||||
// }
|
||||
|
||||
// if (!sql.Strip(wxString::both).EndsWith(wxT(";")))
|
||||
// sql += wxT(";");
|
||||
|
||||
// size_t i;
|
||||
// for (i = 0 ; i < configList.GetCount() ; i++)
|
||||
// {
|
||||
// if (configList.Item(i).BeforeFirst('=') != wxT("search_path") &&
|
||||
// configList.Item(i).BeforeFirst('=') != wxT("temp_tablespaces"))
|
||||
// sql += wxT("\nALTER FUNCTION ") + qtSig
|
||||
// + wxT(" SET ") + configList.Item(i).BeforeFirst('=') + wxT("='") + configList.Item(i).AfterFirst('=') + wxT("';\n");
|
||||
// else
|
||||
// sql += wxT("\nALTER FUNCTION ") + qtSig
|
||||
// + wxT(" SET ") + configList.Item(i).BeforeFirst('=') + wxT("=") + configList.Item(i).AfterFirst('=') + wxT(";\n");
|
||||
// }
|
||||
|
||||
// sql += wxT("\n")
|
||||
// + GetOwnerSql(8, 0, wxT("FUNCTION ") + qtSig)
|
||||
// + GetGrant(wxT("X"), wxT("FUNCTION ") + qtSig);
|
||||
|
||||
// if (!GetComment().IsNull())
|
||||
// {
|
||||
// sql += wxT("COMMENT ON FUNCTION ") + qtSig
|
||||
// + wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n");
|
||||
// }
|
||||
|
||||
// if (GetConnection()->BackendMinimumVersion(9, 1))
|
||||
// sql += GetSeqLabelsSql();
|
||||
|
||||
createSqlCache = std::move(sql);
|
||||
}
|
||||
|
||||
return createSqlCache;
|
||||
}
|
||||
87
pglablib/catalog/PgProc.h
Normal file
87
pglablib/catalog/PgProc.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef PGPROC_H
|
||||
#define PGPROC_H
|
||||
|
||||
#include "PgNamespaceObject.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include "Pgsql_Value.h"
|
||||
#include <vector>
|
||||
|
||||
class Arg {
|
||||
public:
|
||||
enum Mode {
|
||||
In, Out, InOut, Variadic, Table
|
||||
};
|
||||
|
||||
Oid type;
|
||||
Mode mode;
|
||||
QString name;
|
||||
QString def;
|
||||
|
||||
Arg(Oid t, Mode m, QString n, QString d)
|
||||
: type(t), mode(m), name(n), def(d)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
class PgProc: public PgNamespaceObject {
|
||||
public:
|
||||
using PgNamespaceObject::PgNamespaceObject;
|
||||
|
||||
// Oid oid = InvalidOid; // oid
|
||||
// QString name; // name
|
||||
// Oid pronamespace = InvalidOid; // oid, namespace
|
||||
Oid owner = InvalidOid; // oid
|
||||
Oid lang = InvalidOid; // oid
|
||||
float cost = 0.f; // float4
|
||||
float rows = 0.f; // float4
|
||||
Oid variadic = InvalidOid; // oid
|
||||
QString transform; // regproc
|
||||
bool isagg = false; // bool
|
||||
bool iswindow = false; // bool
|
||||
bool secdef = false; // bool
|
||||
bool leakproof = false; // bool
|
||||
bool isstrict = false; // bool
|
||||
bool retset = false; // bool
|
||||
char provolatile = '\0'; // char
|
||||
char parallel = '\0'; // char, version >= 9.6
|
||||
int16_t nargs = 0; // int2
|
||||
int16_t nargdefaults; // = 0; // int2
|
||||
Oid rettype = InvalidOid; // oid
|
||||
std::vector<Oid> trftypes; // oid[], version >= 9.5
|
||||
QString src; // text
|
||||
QString bin; // text
|
||||
std::vector<QString> config; // text[]
|
||||
QString acl; // aclitem[]
|
||||
|
||||
/// Converts the collection of arrays about the arguments to a single list of arguments
|
||||
/// making it much easier to work with them correctly
|
||||
void setArgs(
|
||||
std::vector<Oid> argtypes,
|
||||
std::vector<Oid> allargtypes,
|
||||
std::vector<char> argmodes,
|
||||
std::vector<QString> argnames,
|
||||
std::optional<QString> argdefaults
|
||||
);
|
||||
const std::vector<Arg>& args() const;
|
||||
|
||||
// bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
// bool operator==(const QString &n) const { return name == n; }
|
||||
// bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
// bool operator<(const PgProc &rhs) const { return oid < rhs.oid; }
|
||||
|
||||
QString createSql() const;
|
||||
QString argListWithNames(bool multiline = false) const;
|
||||
QString argSigList(const bool forScript = false) const;
|
||||
|
||||
// bool isTrigger() const
|
||||
// {
|
||||
// return typname == wxT("\"trigger\"") || typname == wxT("trigger") || typname == wxT("event_trigger") || typname == wxT("\"event_trigger\""))
|
||||
// }
|
||||
private:
|
||||
mutable QString createSqlCache;
|
||||
|
||||
std::vector<Arg> m_args;
|
||||
};
|
||||
|
||||
#endif // PGPROC_H
|
||||
59
pglablib/catalog/PgProcContainer.cpp
Normal file
59
pglablib/catalog/PgProcContainer.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include "PgProcContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
std::string PgProcContainer::getLoadQuery() const
|
||||
{
|
||||
std::string column_list =
|
||||
"oid,proname,pronamespace,proowner,prolang,procost,prorows,"
|
||||
"provariadic,protransform,proisagg,proiswindow,prosecdef,proleakproof,"
|
||||
"proisstrict,proretset,provolatile,pronargs,pronargdefaults,prorettype,"
|
||||
"proargtypes,proallargtypes,proargmodes,proargnames,proargdefaults,"
|
||||
"prosrc,probin,proconfig,proacl";
|
||||
if (minimumVersion(90500)) {
|
||||
column_list += ",protrftypes";
|
||||
}
|
||||
if (minimumVersion(90600)) {
|
||||
column_list += ",proparallel";
|
||||
}
|
||||
|
||||
return "SELECT " + column_list + " FROM pg_proc";
|
||||
}
|
||||
|
||||
PgProc PgProcContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
Oid oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
Oid namespace_oid = col.nextValue();
|
||||
|
||||
PgProc v(m_catalog, oid, name, namespace_oid);
|
||||
|
||||
col >> v.owner >> v.lang >> v.cost >> v.rows
|
||||
>> v.variadic >> v.transform >> v.isagg >> v.iswindow >> v.secdef >> v.leakproof
|
||||
>> v.isstrict >> v.retset >> v.provolatile >> v.nargs >> v.nargdefaults
|
||||
>> v.rettype;
|
||||
|
||||
std::vector<Oid> argtypes; // oid[]
|
||||
std::vector<Oid> allargtypes; // oid[]
|
||||
std::vector<char> argmodes; // char[]
|
||||
std::vector<QString> argnames; // text[]
|
||||
std::optional<QString> argdefaults; // pg_node_tree
|
||||
col.getAsVector<Oid>(std::back_inserter(argtypes));
|
||||
col >> allargtypes >> argmodes >> argnames >> argdefaults
|
||||
>> v.src >> v.bin >> v.config >> v.acl;
|
||||
|
||||
v.setArgs(argtypes, allargtypes, argmodes, argnames, argdefaults);
|
||||
|
||||
if (minimumVersion(90500)) {
|
||||
col >> v.trftypes;
|
||||
}
|
||||
if (minimumVersion(90600)) {
|
||||
col >> v.parallel;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
26
pglablib/catalog/PgProcContainer.h
Normal file
26
pglablib/catalog/PgProcContainer.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef PGPROCCONTAINER_H
|
||||
#define PGPROCCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgProc.h"
|
||||
#include <vector>
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
class PgProcContainer: public PgContainer<PgProc> {
|
||||
public:
|
||||
using PgContainer<PgProc>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
|
||||
//std::vector<PgProc> getTriggersForRelation(Oid cls) const;
|
||||
protected:
|
||||
PgProc loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // PGPROCCONTAINER_H
|
||||
2
pglablib/catalog/PgServerObject.cpp
Normal file
2
pglablib/catalog/PgServerObject.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#include "PgServerObject.h"
|
||||
|
||||
15
pglablib/catalog/PgServerObject.h
Normal file
15
pglablib/catalog/PgServerObject.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef PGSERVEROBJECT_H
|
||||
#define PGSERVEROBJECT_H
|
||||
|
||||
#include <QString>
|
||||
#include "PgObject.h"
|
||||
|
||||
|
||||
/// Base object for objects that belong to a server
|
||||
class PgServerObject: public PgObject {
|
||||
public:
|
||||
using PgObject::PgObject;
|
||||
|
||||
};
|
||||
|
||||
#endif // PGSERVEROBJECT_H
|
||||
4
pglablib/catalog/PgTablespace.cpp
Normal file
4
pglablib/catalog/PgTablespace.cpp
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#include "PgTablespace.h"
|
||||
|
||||
PgTablespace::PgTablespace()
|
||||
{}
|
||||
24
pglablib/catalog/PgTablespace.h
Normal file
24
pglablib/catalog/PgTablespace.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef PGTABLESPACE_H
|
||||
#define PGTABLESPACE_H
|
||||
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include <vector>
|
||||
|
||||
class PgTablespace {
|
||||
public:
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
Oid owner = InvalidOid;
|
||||
std::vector<QString> acl;
|
||||
std::vector<QString> options;
|
||||
|
||||
PgTablespace();
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
//bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgTablespace &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGTABLESPACE_H
|
||||
23
pglablib/catalog/PgTablespaceContainer.cpp
Normal file
23
pglablib/catalog/PgTablespaceContainer.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include "PgTablespaceContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include <iterator>
|
||||
|
||||
std::string PgTablespaceContainer::getLoadQuery() const
|
||||
{
|
||||
return
|
||||
R"__SQL__(
|
||||
SELECT oid, spcname, spcowner, spcacl, spcoptions
|
||||
FROM pg_tablespace
|
||||
)__SQL__";
|
||||
}
|
||||
|
||||
PgTablespace PgTablespaceContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgTablespace v;
|
||||
col >> v.oid >> v.name >> v.owner >> v.acl >> v.options;
|
||||
return v;
|
||||
}
|
||||
24
pglablib/catalog/PgTablespaceContainer.h
Normal file
24
pglablib/catalog/PgTablespaceContainer.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef PGTABLESPACECONTAINER_H
|
||||
#define PGTABLESPACECONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgTablespace.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgTablespaceContainer: public PgContainer<PgTablespace> {
|
||||
public:
|
||||
using PgContainer<PgTablespace>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
PgTablespace loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // PGTABLESPACECONTAINER_H
|
||||
156
pglablib/catalog/PgTrigger.cpp
Normal file
156
pglablib/catalog/PgTrigger.cpp
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#include "PgTrigger.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgProcContainer.h"
|
||||
#include "SqlFormattingUtils.h"
|
||||
#include <QStringBuilder>
|
||||
|
||||
QString PgTrigger::dropSql()
|
||||
{
|
||||
if (m_dropSql.isEmpty()) {
|
||||
auto&& fqtablename = catalog().classes()->getByKey(relid)->fullyQualifiedQuotedObjectName(); // genFQTableName(catalog(), *catalog().classes()->getByKey(relid));
|
||||
m_dropSql = "DROP TRIGGER " % quotedObjectName()
|
||||
% " ON " % fqtablename % ";";
|
||||
}
|
||||
return m_dropSql;
|
||||
}
|
||||
|
||||
QString PgTrigger::createSql()
|
||||
{
|
||||
if (m_createSql.isEmpty()) {
|
||||
auto&& fqtablename = catalog().classes()->getByKey(relid)->fullyQualifiedQuotedObjectName(); //genFQTableName(catalog(), *catalog().classes()->getByKey(relid));
|
||||
auto&& triggername = quotedObjectName();
|
||||
|
||||
if (constraint != InvalidOid)
|
||||
m_createSql += "CREATE CONSTRAINT TRIGGER ";
|
||||
else
|
||||
m_createSql += "CREATE TRIGGER ";
|
||||
|
||||
m_createSql += triggername + "\n "
|
||||
+ typeFireWhen()
|
||||
+ " " + event();
|
||||
|
||||
m_createSql += "\n ON " + fqtablename;
|
||||
if (deferrable) {
|
||||
m_createSql += "\n DEFERRABLE INITIALLY ";
|
||||
if (initdeferred)
|
||||
m_createSql += "DEFERRED";
|
||||
else
|
||||
m_createSql += "IMMEDIATE";
|
||||
}
|
||||
m_createSql += "\n FOR EACH " + forEach();
|
||||
|
||||
// requires atleast 8.5 don;t think we have to support older
|
||||
if (!whenclause.isEmpty())
|
||||
m_createSql += "\n WHEN (" + whenclause + ")";
|
||||
|
||||
m_createSql += QString("\n EXECUTE PROCEDURE %1;\n").arg(procedure());
|
||||
|
||||
if (!enabled)
|
||||
m_createSql += QString("ALTER TABLE %1 DISABLE TRIGGER %2;\n").arg(fqtablename, triggername);
|
||||
|
||||
// if (!GetComment().IsEmpty())
|
||||
// sql += wxT("COMMENT ON TRIGGER ") + GetQuotedIdentifier() + wxT(" ON ") + GetQuotedFullTable()
|
||||
// + wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n");
|
||||
}
|
||||
|
||||
return m_createSql;
|
||||
}
|
||||
|
||||
|
||||
QString PgTrigger::typeFireWhen() const
|
||||
{
|
||||
QString when;
|
||||
|
||||
if (type & TriggerTypeBefore)
|
||||
when = "BEFORE";
|
||||
else if (type & TriggerTypeInstead)
|
||||
when = "INSTEAD OF";
|
||||
else
|
||||
when = "AFTER";
|
||||
return when;
|
||||
}
|
||||
|
||||
|
||||
QString PgTrigger::eventAbbr() const
|
||||
{
|
||||
QString event;
|
||||
if (type & TriggerTypeInsert)
|
||||
event += "I";
|
||||
if (type & TriggerTypeUpdate)
|
||||
event += "U";
|
||||
if (type & TriggerTypeDelete)
|
||||
event += "D";
|
||||
if (type & TriggerTypeTruncate)
|
||||
event += "T";
|
||||
return event;
|
||||
}
|
||||
|
||||
QString PgTrigger::event() const
|
||||
{
|
||||
QString event;
|
||||
if (type & TriggerTypeInsert)
|
||||
event += "INSERT ";
|
||||
if (type & TriggerTypeUpdate)
|
||||
event += "UPDATE ";
|
||||
if (type & TriggerTypeDelete)
|
||||
event += "DELETE ";
|
||||
if (type & TriggerTypeTruncate)
|
||||
event += "TRUNCATE";
|
||||
return event.trimmed();
|
||||
}
|
||||
|
||||
QString PgTrigger::forEach() const
|
||||
{
|
||||
if (isRow())
|
||||
return "ROW";
|
||||
else
|
||||
return "STATEMENT";
|
||||
}
|
||||
|
||||
QString PgTrigger::procedure() const
|
||||
{
|
||||
const PgProc *proc = catalog().procs()->getByKey(foid);
|
||||
QString func_name = proc->fullyQualifiedQuotedObjectName();
|
||||
return QString("%1(%2)").arg(func_name, arguments());
|
||||
}
|
||||
|
||||
QString PgTrigger::arguments() const
|
||||
{
|
||||
QString arglist;
|
||||
|
||||
if (nargs > 0)
|
||||
arglist = args;
|
||||
|
||||
QString output;
|
||||
while (!arglist.isEmpty()) {
|
||||
int pos = arglist.indexOf(QChar::Null);
|
||||
if (pos != 0) {
|
||||
QString arg;
|
||||
if (pos > 0)
|
||||
arg = arglist.left(pos);
|
||||
else
|
||||
arg = arglist;
|
||||
|
||||
if (!output.isEmpty())
|
||||
output += ", ";
|
||||
|
||||
bool conversion_ok = false;
|
||||
arg.toLongLong(&conversion_ok);
|
||||
if (conversion_ok)
|
||||
output += arg;
|
||||
else
|
||||
output += escapeLiteral(arg);
|
||||
}
|
||||
else {
|
||||
if (!output.isEmpty())
|
||||
output += ", ";
|
||||
output += escapeLiteral(QString());
|
||||
}
|
||||
if (pos >= 0)
|
||||
arglist = arglist.mid(pos + 4);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
71
pglablib/catalog/PgTrigger.h
Normal file
71
pglablib/catalog/PgTrigger.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef PGTRIGGER_H
|
||||
#define PGTRIGGER_H
|
||||
|
||||
#include "PgNamespaceObject.h"
|
||||
#include "Pgsql_Value.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class PgTrigger: public PgNamespaceObject {
|
||||
public:
|
||||
// Oid oid = InvalidOid;
|
||||
Oid relid;
|
||||
// QString name;
|
||||
Oid foid;
|
||||
int16_t type;
|
||||
char enabled;
|
||||
bool isinternal;
|
||||
Oid constrrelid;
|
||||
Oid constrindid;
|
||||
Oid constraint;
|
||||
bool deferrable;
|
||||
bool initdeferred;
|
||||
int16_t nargs;
|
||||
QString attr;
|
||||
QString args;
|
||||
QString whenclause;
|
||||
QString oldtable; // >= 10.0
|
||||
QString newtable; // >= 10.0
|
||||
|
||||
using PgNamespaceObject::PgNamespaceObject;
|
||||
|
||||
// virtual QString objectName() const override;
|
||||
|
||||
|
||||
// bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
// bool operator==(const QString &n) const { return name == n; }
|
||||
// bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
// bool operator<(const PgTrigger &rhs) const { return oid < rhs.oid; }
|
||||
|
||||
static constexpr int TriggerTypeRow = (1 << 0);
|
||||
static constexpr int TriggerTypeBefore = (1 << 1);
|
||||
static constexpr int TriggerTypeInsert = (1 << 2);
|
||||
static constexpr int TriggerTypeDelete = (1 << 3);
|
||||
static constexpr int TriggerTypeUpdate = (1 << 4);
|
||||
static constexpr int TriggerTypeTruncate = (1 << 5);
|
||||
static constexpr int TriggerTypeInstead = (1 << 6);
|
||||
|
||||
QString dropSql();
|
||||
QString createSql();
|
||||
bool isRow() const { return type & TriggerTypeRow; }
|
||||
bool isBefore() const { return type & TriggerTypeBefore; }
|
||||
QString typeFireWhen() const;
|
||||
QString eventAbbr() const;
|
||||
QString event() const;
|
||||
QString forEach() const;
|
||||
QString procedure() const;
|
||||
|
||||
//wxString pgTrigger::GetForEach() const
|
||||
//{
|
||||
// return (triggerType & TRIGGER_TYPE_ROW) ? wxT("ROW") : wxT("STATEMENT");
|
||||
//}
|
||||
|
||||
QString arguments() const;
|
||||
private:
|
||||
mutable QString m_dropSql; // cache
|
||||
mutable QString m_createSql; // cache
|
||||
};
|
||||
|
||||
#endif // PGTRIGGER_H
|
||||
56
pglablib/catalog/PgTriggerContainer.cpp
Normal file
56
pglablib/catalog/PgTriggerContainer.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "PgTriggerContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
std::string PgTriggerContainer::getLoadQuery() const
|
||||
{
|
||||
std::string q =
|
||||
"SELECT oid, tgname, tgrelid, tgfoid, tgtype, tgenabled, tgisinternal, tgconstrrelid, \n"
|
||||
" tgconstrindid, tgconstraint, tgdeferrable, tginitdeferred, tgnargs, tgattr, \n"
|
||||
" tgargs, COALESCE(substring(pg_get_triggerdef(oid), 'WHEN (.*) EXECUTE PROCEDURE'), substring(pg_get_triggerdef(oid), 'WHEN (.*) \\$trigger')) AS whenclause";
|
||||
if (minimumVersion(90600)) {
|
||||
q += ", tgoldtable, tgnewtable";
|
||||
}
|
||||
q +=
|
||||
" FROM pg_trigger \n"
|
||||
" WHERE NOT tgisinternal";
|
||||
return q;
|
||||
}
|
||||
|
||||
PgTrigger PgTriggerContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
|
||||
Pgsql::Col col(row);
|
||||
Oid oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
PgTrigger v(m_catalog, oid, name, InvalidOid);
|
||||
col >> v.relid >> v.foid >> v.type >> v.enabled >> v.isinternal >> v.constrrelid
|
||||
>> v.constrindid >> v.constraint >> v.deferrable >> v.initdeferred >> v.nargs >> v.attr;
|
||||
const unsigned char * args_bytea = reinterpret_cast<const unsigned char *>(col.nextValue().c_str());
|
||||
if (args_bytea) {
|
||||
size_t to_length;
|
||||
unsigned char *result = PQunescapeBytea(args_bytea, &to_length);
|
||||
if (result) {
|
||||
v.args = QString::fromUtf8(reinterpret_cast<const char*>(result), static_cast<int>(to_length));
|
||||
PQfreemem(result);
|
||||
}
|
||||
}
|
||||
col >> v.whenclause;
|
||||
if (minimumVersion(90600)) {
|
||||
col >> v.oldtable >> v.newtable;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
std::vector<PgTrigger> PgTriggerContainer::getTriggersForRelation(Oid cls) const
|
||||
{
|
||||
std::vector<PgTrigger> result;
|
||||
for (auto e : m_container)
|
||||
if (e.relid == cls)
|
||||
result.push_back(e);
|
||||
|
||||
return result;
|
||||
}
|
||||
28
pglablib/catalog/PgTriggerContainer.h
Normal file
28
pglablib/catalog/PgTriggerContainer.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef PGTRIGGERCONTAINER_H
|
||||
#define PGTRIGGERCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgTrigger.h"
|
||||
#include <vector>
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgTriggerContainer: public PgContainer<PgTrigger> {
|
||||
public:
|
||||
using PgContainer<PgTrigger>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
|
||||
std::vector<PgTrigger> getTriggersForRelation(Oid cls) const;
|
||||
protected:
|
||||
PgTrigger loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGTRIGGERCONTAINER_H
|
||||
52
pglablib/catalog/PgType.cpp
Normal file
52
pglablib/catalog/PgType.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#include "PgType.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
|
||||
void operator<<(TypCategory &s, const Pgsql::Value &v)
|
||||
{
|
||||
//s = static_cast<T>(v);
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'A':
|
||||
s = TypCategory::Array;
|
||||
break;
|
||||
case 'B':
|
||||
s = TypCategory::Boolean;
|
||||
break;
|
||||
case 'D':
|
||||
s = TypCategory::DateTime;
|
||||
break;
|
||||
case 'E':
|
||||
s = TypCategory::Enum;
|
||||
break;
|
||||
case 'G':
|
||||
s = TypCategory::Geometric;
|
||||
break;
|
||||
case 'I':
|
||||
s = TypCategory::NetworkAddress;
|
||||
break;
|
||||
case 'N':
|
||||
s = TypCategory::Numeric;
|
||||
break;
|
||||
case 'P':
|
||||
s = TypCategory::Pseudo;
|
||||
break;
|
||||
case 'R':
|
||||
s = TypCategory::Range;
|
||||
break;
|
||||
case 'S':
|
||||
s = TypCategory::String;
|
||||
break;
|
||||
case 'T':
|
||||
s = TypCategory::Timespan;
|
||||
break;
|
||||
case 'U':
|
||||
s = TypCategory::UserDefined;
|
||||
break;
|
||||
case 'V':
|
||||
s = TypCategory::BitString;
|
||||
break;
|
||||
case 'X':
|
||||
s = TypCategory::Unknown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
74
pglablib/catalog/PgType.h
Normal file
74
pglablib/catalog/PgType.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#ifndef PGTYPE_H
|
||||
#define PGTYPE_H
|
||||
|
||||
#include "PgNamespaceObject.h"
|
||||
#include "PgOwnedObject.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include "Pgsql_Value.h"
|
||||
|
||||
enum class TypCategory {
|
||||
Array,
|
||||
Boolean,
|
||||
Composite,
|
||||
DateTime,
|
||||
Enum,
|
||||
Geometric,
|
||||
NetworkAddress,
|
||||
Numeric,
|
||||
Pseudo,
|
||||
Range,
|
||||
String,
|
||||
Timespan,
|
||||
UserDefined,
|
||||
BitString,
|
||||
Unknown
|
||||
};
|
||||
|
||||
void operator<<(TypCategory &s, const Pgsql::Value &v);
|
||||
|
||||
|
||||
class PgType: public PgNamespaceObject, public PgOwnedObject {
|
||||
public:
|
||||
// Oid oid = InvalidOid;
|
||||
// QString name; // formatted name as per database, arrays
|
||||
QString typname; //"name";"NO"
|
||||
// Oid typnamespace = InvalidOid;//"oid";"NO"
|
||||
// Oid owner = InvalidOid;//"oid";"NO"
|
||||
short len = -1;//"smallint";"NO"
|
||||
bool byval = false;//"boolean";"NO"
|
||||
QString type;//""char"";"NO"
|
||||
TypCategory category;//""char"";"NO"
|
||||
bool ispreferred = false;//"boolean";"NO"
|
||||
bool isdefined = false;//"boolean";"NO"
|
||||
QString delim;//""char"";"NO"
|
||||
Oid relid = InvalidOid;//"oid";"NO"
|
||||
Oid elem = InvalidOid;//"oid";"NO"
|
||||
Oid array = InvalidOid;//"oid";"NO"
|
||||
QString input;//regproc";"NO"
|
||||
QString output;//"regproc";"NO"
|
||||
QString receive;//"regproc";"NO"
|
||||
QString send;//"regproc";"NO"
|
||||
QString modin;//"regproc";"NO"
|
||||
QString modout;//"regproc";"NO"
|
||||
QString analyze;//"regproc";"NO"
|
||||
QString align;//""char"";"NO"
|
||||
QString storage;//""char"";"NO"
|
||||
bool notnull = false;//"boolean";"NO"
|
||||
Oid basetype = InvalidOid;//"oid";"NO"
|
||||
int typmod = -1;//"integer";"NO"
|
||||
int ndims = 0;//"integer";"NO"
|
||||
Oid collation = InvalidOid;//"oid";"NO"
|
||||
QString defaultbin;//"pg_node_tree";"YES"
|
||||
QString typdefault;//"text";"YES"
|
||||
QString acl;//"ARRAY";"YES"
|
||||
|
||||
using PgNamespaceObject::PgNamespaceObject;
|
||||
|
||||
// bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
// bool operator==(const QString &n) const { return name == n; }
|
||||
// bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
// bool operator<(const PgType &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGTYPE_H
|
||||
31
pglablib/catalog/PgTypeContainer.cpp
Normal file
31
pglablib/catalog/PgTypeContainer.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "PgTypeContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
std::string PgTypeContainer::getLoadQuery() const
|
||||
{
|
||||
return
|
||||
"SELECT oid, format_type(oid, NULL) AS name, typnamespace, typowner, typname, typlen, typbyval, typtype, typcategory, \n"
|
||||
" typispreferred, typisdefined, typdelim, typrelid, typelem, typarray, typinput, typoutput, \n"
|
||||
" typreceive, typsend, typmodin, typmodout, typanalyze, typalign, typstorage, typnotnull, \n"
|
||||
" typbasetype, typtypmod, typndims, typcollation, typdefaultbin, typdefault, typacl \n"
|
||||
"FROM pg_type";
|
||||
}
|
||||
|
||||
PgType PgTypeContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
Oid type_oid = col.nextValue();
|
||||
QString name = col.nextValue();
|
||||
Oid ns_oid = col.nextValue();
|
||||
Oid owner = col.nextValue();
|
||||
PgType v(m_catalog, type_oid, name, ns_oid);
|
||||
col >> v.typname >> v.len >> v.byval >> v.type >> v.category
|
||||
>> v.ispreferred >> v.isdefined >> v.delim >> v.relid >> v.elem >> v.array >> v.input >> v.output
|
||||
>> v.receive >> v.send >> v.modin >> v.modout >> v.analyze >> v.align >> v.storage >> v.notnull
|
||||
>> v.basetype >> v.typmod >> v.ndims >> v.collation >> v.defaultbin >> v.typdefault >> v.acl;
|
||||
v.setOwnerOid(m_catalog, owner);
|
||||
return v;
|
||||
}
|
||||
33
pglablib/catalog/PgTypeContainer.h
Normal file
33
pglablib/catalog/PgTypeContainer.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef PGTYPECONTAINER_H
|
||||
#define PGTYPECONTAINER_H
|
||||
|
||||
#include "PgType.h"
|
||||
#include "PgContainer.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
class PgTypeContainer: public PgContainer<PgType> {
|
||||
public:
|
||||
using PgContainer<PgType>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
|
||||
/** Searches for the type matching the specified oid.
|
||||
*
|
||||
* \return Returns the matching type or if it is not found a default constructed PgType (oid == InvalidOid).
|
||||
*/
|
||||
// const PgType& getTypeByOid(Oid oid) const;
|
||||
// const PgType& getTypeByName(const QString &name) const;
|
||||
// const PgType& getTypeByIdx(int idx) const;
|
||||
protected:
|
||||
virtual PgType loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
// PgType m_invalidType; ///< default constructed object for when a non existent type is being retrieved.
|
||||
// t_Types m_types; // Keep sorted by Oid
|
||||
};
|
||||
|
||||
#endif // PGTYPECONTAINER_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue