Generate PARTITIONED BY SQL for partitioned tables.

Expressions not yet supported.
This commit is contained in:
eelke 2023-02-06 20:03:57 +01:00
parent 61f90668d8
commit 2c899bd799
8 changed files with 243 additions and 41 deletions

View file

@ -1,4 +1,5 @@
#include "PgClass.h"
#include "PgAttribute.h"
#include "PgAttributeContainer.h"
#include "PgClassContainer.h"
#include "PgDatabaseCatalog.h"
@ -7,6 +8,7 @@
#include <QStringBuilder>
#include "SqlFormattingUtils.h"
#include <ranges>
#include <cassert>
void operator<<(RelPersistence &s, const Pgsql::Value &v)
@ -33,41 +35,60 @@ void operator<<(RelKind &s, const Pgsql::Value &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;
case 'p':
s = RelKind::PartitionedTable;
break;
case 'I':
s = RelKind::PartitionedIndex;
break;
default:
throw std::runtime_error("Unknown RelKind");
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;
case 'p':
s = RelKind::PartitionedTable;
break;
case 'I':
s = RelKind::PartitionedIndex;
break;
default:
throw std::runtime_error("Unknown RelKind");
}
}
void operator<<(PartitioningStrategy &s, const Pgsql::Value &v)
{
const char *c = v.c_str();
switch (*c)
{
case 'h':
s = PartitioningStrategy::Hash;
break;
case 'l':
s = PartitioningStrategy::List;
break;
case 'r':
s = PartitioningStrategy::Range;
break;
default:
throw std::runtime_error("Unknown PartitioningStrategy");
}
}
QString PgClass::createSql() const
{
if (createSqlCache.isEmpty())
@ -75,6 +96,7 @@ QString PgClass::createSql() const
switch (kind)
{
case RelKind::Table:
case RelKind::PartitionedTable:
createSqlCache = createTableSql();
break;
case RelKind::View:
@ -118,7 +140,7 @@ QString PgClass::ddlTypeName() const
{
switch (kind)
{
case RelKind::PartitionedTable: return "PARTITIONED TABLE";
case RelKind::PartitionedTable:
return "TABLE";
default:
return PgNamespaceObject::ddlTypeName();
@ -145,7 +167,9 @@ QString PgClass::createTableSql() const
else
sql += generateBodySql(false);
sql += generateInheritsSql()
% partitionBySql()
% generateTablespaceSql()
% ";\n";
return sql;
@ -238,6 +262,49 @@ QString PgClass::generateInheritsSql() const
return sql;
}
QString PgClass::partitionBySql() const
{
if (kind != RelKind::PartitionedTable)
return {};
QString sql = "\nPARTITION BY " % PartitionStrategyKeyword(partitionedTable.strategy);
sql += partitionKeySql();
return sql;
}
QString PgClass::partitionKeySql() const
{
QString result;
result += "(";
auto keyItem = partitionedTable.keyColumns.begin();
if (keyItem != partitionedTable.keyColumns.end())
{
result += partitionKeyItemSql(*keyItem);
for (++keyItem; keyItem != partitionedTable.keyColumns.end(); ++keyItem)
result += ", " % partitionKeyItemSql(*keyItem);
}
result += ")";
return result;
}
QString PgClass::partitionKeyItemSql(
const PartitioningKeyItem &keyItem
) const
{
if (keyItem.attNum == 0)
return "\"<expr>\""; // TODO add expression support for now use this to prevent a crash here because column 0 does not exist
const PgAttribute *col = catalog().attributes()->findIf(
[this, &keyItem] (const auto &att)
{
return att.relid == oid() && att.num == keyItem.attNum;
}
);
assert(col != nullptr);
return quoteIdent(col->name);
}
QString PgClass::getPartitionOfName() const
{
auto parents = catalog().inherits()->getParentsOf(oid());
@ -274,4 +341,15 @@ QString PgClass::createViewSql() const
return sql;
}
QString PartitionStrategyKeyword(PartitioningStrategy ps)
{
switch (ps) {
case PartitioningStrategy::Hash:
return "HASH";
case PartitioningStrategy::List:
return "LIST";
case PartitioningStrategy::Range:
return "RANGE";
}
throw std::runtime_error("Unknown PartitioningStrategy");
}