New column page

Shows SQL for columns ALTER TABLE ... [ADD|DROP] COLUMN combines a selection
of multiple columns into a single alter table.
Show collation in list of columns.

(order of columns isn't what is should be but that should maybe be fixed
by a generic column selection and ordering mechanism that knows what the
default sort should be)
This commit is contained in:
eelke 2018-11-29 20:21:36 +01:00
parent 73c4cf4790
commit 57217974f4
19 changed files with 345 additions and 55 deletions

View file

@ -1,2 +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->name;
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;
}

View file

@ -6,11 +6,13 @@
#include <libpq-fe.h>
#include <tuple>
class PgClass;
class PgDatabaseCatalog;
class PgAttribute {
public:
using Key = std::tuple<Oid, int16_t>;
// Oid oid = InvalidOid;
Oid relid = InvalidOid;
QString name;
Oid typid = InvalidOid;
@ -20,6 +22,7 @@ public:
int32_t typmod = -1;
bool notnull = false;
bool hasdef = false;
char identity = ' ';
bool isdropped = false;
Oid collation = InvalidOid;
QString acl;
@ -33,6 +36,10 @@ public:
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

View file

@ -1,5 +1,6 @@
#include "PgAttributeContainer.h"
#include "Pgsql_Col.h"
#include "PgDatabaseCatalog.h"
//SELECT attname, pg_get_expr(adbin, adrelid) AS def_value
//FROM pg_attribute
@ -8,12 +9,16 @@
std::string PgAttributeContainer::getLoadQuery() const
{
return R"__(
std::string q = R"__(
SELECT attrelid, attname, atttypid, attstattarget,
attnum, attndims, atttypmod, attnotnull, atthasdef, attisdropped,
attcollation, attacl, attoptions, pg_get_expr(adbin, adrelid) AS def_value
FROM pg_catalog.pg_attribute
LEFT JOIN pg_attrdef ON attrelid=adrelid AND attnum=adnum)__";
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)
@ -23,6 +28,9 @@ PgAttribute PgAttributeContainer::loadElem(const Pgsql::Row &row)
col >> v.relid >> v.name >> v.typid >> v.stattarget
>> v.num >> v.ndims >> v.typmod >> v.notnull >> v.hasdef >> v.isdropped
>> v.collation >> v.acl >> v.options >> v.defaultValue;
if (m_catalog.serverVersion() >= 100000)
col >> v.identity;
return v;
}

2
pglablib/PgCollation.cpp Normal file
View file

@ -0,0 +1,2 @@
#include "PgCollation.h"

25
pglablib/PgCollation.h Normal file
View 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

View 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;
}

View 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

View file

@ -13,6 +13,7 @@
#include "PgTriggerContainer.h"
#include "PgTypeContainer.h"
#include "PgProcContainer.h"
#include "PgCollationContainer.h"
#include "Pgsql_Connection.h"
#include "Pgsql_oids.h"
@ -160,6 +161,9 @@ void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn,
// 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
@ -294,3 +298,8 @@ std::shared_ptr<const PgProcContainer> PgDatabaseCatalog::procs() const
{
return m_procs;
}
std::shared_ptr<const PgCollationContainer> PgDatabaseCatalog::collations() const
{
return m_collations;
}

View file

@ -27,6 +27,8 @@ class PgTablespaceContainer;
class PgTriggerContainer;
class PgTypeContainer;
class PgProcContainer;
class PgCollationContainer;
class PgDatabaseCatalog: public QObject, public std::enable_shared_from_this<PgDatabaseCatalog> {
Q_OBJECT
@ -57,6 +59,7 @@ public:
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;
enum RefreshFlag {
Attributes = 1,
@ -94,6 +97,7 @@ private:
std::shared_ptr<PgTriggerContainer> m_triggers;
std::shared_ptr<PgTypeContainer> m_types;
std::shared_ptr<PgProcContainer> m_procs;
std::shared_ptr<PgCollationContainer> m_collations;
template <typename T>
void load2(std::shared_ptr<T> &ptr, Pgsql::Connection &conn)

View file

@ -195,7 +195,7 @@ bool identNeedsQuotes(QString ident)
if (ident[0].isDigit())
return true;
for (auto c : ident)
if ((c < 'a' || c > 'z') && c != '_')
if ((c < 'a' || c > 'z') && c != '_' && (c < '0' || c > '9'))
return true;
auto kw = getPgsqlKeyword(ident);

View file

@ -71,7 +71,9 @@ codebuilder/StructureTemplate.cpp \
PgDatabaseObject.cpp \
PgServerObject.cpp \
PgOwnedObject.cpp \
PgNamespaceObject.cpp
PgNamespaceObject.cpp \
PgCollation.cpp \
PgCollationContainer.cpp
HEADERS += \
Pglablib.h \
@ -125,7 +127,9 @@ codebuilder/StructureTemplate.h \
PgDatabaseObject.h \
PgServerObject.h \
PgOwnedObject.h \
PgNamespaceObject.h
PgNamespaceObject.h \
PgCollation.h \
PgCollationContainer.h
unix {
target.path = /usr/lib