2018-01-06 21:22:22 +01:00
|
|
|
|
#include "SqlFormattingUtils.h"
|
|
|
|
|
|
#include <QStringBuilder>
|
|
|
|
|
|
|
|
|
|
|
|
#include <cassert>
|
2018-12-16 10:17:59 +01:00
|
|
|
|
#include "catalog/PgKeywordList.h"
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
2018-12-16 10:17:59 +01:00
|
|
|
|
#include "catalog/PgConstraint.h"
|
|
|
|
|
|
#include "catalog/PgAttributeContainer.h"
|
|
|
|
|
|
#include "catalog/PgClass.h"
|
|
|
|
|
|
#include "catalog/PgClassContainer.h"
|
|
|
|
|
|
#include "catalog/PgIndex.h"
|
|
|
|
|
|
#include "catalog/PgNamespace.h"
|
|
|
|
|
|
#include "catalog/PgNamespaceContainer.h"
|
|
|
|
|
|
#include "catalog/PgDatabaseCatalog.h"
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
2018-11-18 19:30:45 +01:00
|
|
|
|
namespace {
|
|
|
|
|
|
|
2022-07-08 19:53:45 +02:00
|
|
|
|
QString escapeInternal(const QString &input, QChar quote_char)
|
2018-11-18 19:30:45 +01:00
|
|
|
|
{
|
2022-07-08 19:53:45 +02:00
|
|
|
|
int num_quotes = 0; /* single or double, depending on as_ident */
|
2018-11-18 19:30:45 +01:00
|
|
|
|
const int len = input.length();
|
2022-07-08 19:53:45 +02:00
|
|
|
|
for (int idx = 0; idx < len; ++idx)
|
|
|
|
|
|
if (input[idx] == quote_char)
|
2018-11-18 19:30:45 +01:00
|
|
|
|
++num_quotes;
|
|
|
|
|
|
|
|
|
|
|
|
int output_size = len + num_quotes + 2; // + 2 for the quotes
|
|
|
|
|
|
|
2022-07-08 19:53:45 +02:00
|
|
|
|
QString output;
|
|
|
|
|
|
output.reserve(output_size);
|
2018-11-18 19:30:45 +01:00
|
|
|
|
output += quote_char;
|
2022-07-08 19:53:45 +02:00
|
|
|
|
if (num_quotes == 0) {
|
2018-11-18 19:30:45 +01:00
|
|
|
|
output += input;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
for (int idx = 0; idx < len; ++idx) {
|
|
|
|
|
|
QChar c = input[idx];
|
|
|
|
|
|
output += c;
|
2022-07-08 19:53:45 +02:00
|
|
|
|
if (c == quote_char)
|
2018-11-18 19:30:45 +01:00
|
|
|
|
output += c;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
output += quote_char;
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString escapeIdent(const QString &input)
|
|
|
|
|
|
{
|
2022-07-08 19:53:45 +02:00
|
|
|
|
return escapeInternal(input, '"');
|
2018-11-18 19:30:45 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString escapeLiteral(const QString &input)
|
|
|
|
|
|
{
|
2022-07-08 19:53:45 +02:00
|
|
|
|
return escapeInternal(input, '\'');
|
2018-11-18 19:30:45 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//char *
|
|
|
|
|
|
//PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// const char *s;
|
|
|
|
|
|
// char *result;
|
|
|
|
|
|
// char *rp;
|
|
|
|
|
|
// int num_quotes = 0; /* single or double, depending on as_ident */
|
|
|
|
|
|
// int num_backslashes = 0;
|
|
|
|
|
|
// int input_len;
|
|
|
|
|
|
// int result_size;
|
|
|
|
|
|
// char quote_char = as_ident ? '"' : '\'';
|
|
|
|
|
|
|
|
|
|
|
|
//// /* We must have a connection, else fail immediately. */
|
|
|
|
|
|
//// if (!conn)
|
|
|
|
|
|
//// return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
// /* Scan the string for characters that must be escaped. */
|
|
|
|
|
|
// for (s = str; (s - str) < len && *s != '\0'; ++s)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (*s == quote_char)
|
|
|
|
|
|
// ++num_quotes;
|
|
|
|
|
|
// else if (*s == '\\')
|
|
|
|
|
|
// ++num_backslashes;
|
|
|
|
|
|
// else if (IS_HIGHBIT_SET(*s))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// int charlen;
|
|
|
|
|
|
|
|
|
|
|
|
// /* Slow path for possible multibyte characters */
|
|
|
|
|
|
// charlen = pg_encoding_mblen(conn->client_encoding, s);
|
|
|
|
|
|
|
|
|
|
|
|
// /* Multibyte character overruns allowable length. */
|
|
|
|
|
|
// if ((s - str) + charlen > len || memchr(s, 0, charlen) != NULL)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
|
// libpq_gettext("incomplete multibyte character\n"));
|
|
|
|
|
|
// return NULL;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// /* Adjust s, bearing in mind that for loop will increment it. */
|
|
|
|
|
|
// s += charlen - 1;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// /* Allocate output buffer. */
|
|
|
|
|
|
// input_len = s - str;
|
|
|
|
|
|
// result_size = input_len + num_quotes + 3; /* two quotes, plus a NUL */
|
|
|
|
|
|
// if (!as_ident && num_backslashes > 0)
|
|
|
|
|
|
// result_size += num_backslashes + 2;
|
|
|
|
|
|
// result = rp = (char *) malloc(result_size);
|
|
|
|
|
|
// if (rp == NULL)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
|
// libpq_gettext("out of memory\n"));
|
|
|
|
|
|
// return NULL;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// /*
|
|
|
|
|
|
// * If we are escaping a literal that contains backslashes, we use the
|
|
|
|
|
|
// * escape string syntax so that the result is correct under either value
|
|
|
|
|
|
// * of standard_conforming_strings. We also emit a leading space in this
|
|
|
|
|
|
// * case, to guard against the possibility that the result might be
|
|
|
|
|
|
// * interpolated immediately following an identifier.
|
|
|
|
|
|
// */
|
|
|
|
|
|
// if (!as_ident && num_backslashes > 0)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// *rp++ = ' ';
|
|
|
|
|
|
// *rp++ = 'E';1
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// /* Opening quote. */
|
|
|
|
|
|
// *rp++ = quote_char;
|
|
|
|
|
|
|
|
|
|
|
|
// /*
|
|
|
|
|
|
// * Use fast path if possible.
|
|
|
|
|
|
// *
|
|
|
|
|
|
// * We've already verified that the input string is well-formed in the
|
|
|
|
|
|
// * current encoding. If it contains no quotes and, in the case of
|
|
|
|
|
|
// * literal-escaping, no backslashes, then we can just copy it directly to
|
|
|
|
|
|
// * the output buffer, adding the necessary quotes.
|
|
|
|
|
|
// *
|
|
|
|
|
|
// * If not, we must rescan the input and process each character
|
|
|
|
|
|
// * individually.
|
|
|
|
|
|
// */
|
|
|
|
|
|
// if (num_quotes == 0 && (num_backslashes == 0 || as_ident))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// memcpy(rp, str, input_len);
|
|
|
|
|
|
// rp += input_len;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// for (s = str; s - str < input_len; ++s)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (*s == quote_char || (!as_ident && *s == '\\'))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// *rp++ = *s;
|
|
|
|
|
|
// *rp++ = *s;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else if (!IS_HIGHBIT_SET(*s))
|
|
|
|
|
|
// *rp++ = *s;
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// int i = pg_encoding_mblen(conn->client_encoding, s);
|
|
|
|
|
|
|
|
|
|
|
|
// while (1)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// *rp++ = *s;
|
|
|
|
|
|
// if (--i == 0)
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// ++s; /* for loop will provide the final increment */
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// /* Closing quote and terminating NUL. */
|
|
|
|
|
|
// *rp++ = quote_char;
|
|
|
|
|
|
// *rp = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
// return result;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
|
|
|
|
|
bool identNeedsQuotes(QString ident)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ident[0].isDigit())
|
|
|
|
|
|
return true;
|
|
|
|
|
|
for (auto c : ident)
|
2018-11-29 20:21:36 +01:00
|
|
|
|
if ((c < 'a' || c > 'z') && c != '_' && (c < '0' || c > '9'))
|
2018-01-06 21:22:22 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
auto kw = getPgsqlKeyword(ident);
|
|
|
|
|
|
if (kw == nullptr)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
else if (kw->getCategory() == UNRESERVED_KEYWORD)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
// if (forTypes && sk->category == COL_NAME_KEYWORD)
|
|
|
|
|
|
// return false;
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString quoteIdent(QString ident)
|
|
|
|
|
|
{
|
|
|
|
|
|
assert(ident.length() > 0);
|
|
|
|
|
|
|
|
|
|
|
|
static const wchar_t dquote = L'"';
|
|
|
|
|
|
|
|
|
|
|
|
if (identNeedsQuotes(ident)) {
|
|
|
|
|
|
QString out;
|
|
|
|
|
|
out += dquote;
|
|
|
|
|
|
out += ident.replace("\"", "\"\"");
|
|
|
|
|
|
out += dquote;
|
|
|
|
|
|
return out;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return ident;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-25 09:06:01 +01:00
|
|
|
|
QString dollarQuoteString(const QString &value)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString def_tag = "BODY";
|
|
|
|
|
|
QString tag = QString("$%1$").arg(def_tag);
|
|
|
|
|
|
|
|
|
|
|
|
int counter = 1;
|
|
|
|
|
|
while (value.indexOf(tag) >= 0)
|
|
|
|
|
|
tag = QString("$%1%2$").arg(def_tag, counter++);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return tag
|
|
|
|
|
|
+ value
|
|
|
|
|
|
+ tag;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-25 19:45:06 +01:00
|
|
|
|
//QString genSchemaPrefix(const PgNamespace &ns)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// QString str;
|
|
|
|
|
|
// if (!ns.name.isEmpty()) {
|
|
|
|
|
|
// str = quoteIdent(ns.name) % QString::fromUtf16(u".");
|
|
|
|
|
|
// }
|
|
|
|
|
|
// return str;
|
|
|
|
|
|
//}
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-25 19:45:06 +01:00
|
|
|
|
//QString genFQTableName(const PgDatabaseCatalog &catalog, const PgClass &cls)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// auto ns = catalog.namespaces()->getByKey(cls.relnamespace);
|
|
|
|
|
|
////cls.fullyQualifiedQuotedObjectName()
|
|
|
|
|
|
// return ns->quotedObjectName() % "." % cls.quotedObjectName();
|
|
|
|
|
|
//}
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
2018-11-30 18:41:38 +01:00
|
|
|
|
QString genAlterTable(const PgDatabaseCatalog &, const PgClass &cls)
|
2018-01-06 21:22:22 +01:00
|
|
|
|
{
|
2018-11-25 19:45:06 +01:00
|
|
|
|
return "ALTER TABLE " % cls.fullyQualifiedQuotedObjectName(); // genFQTableName(catalog, cls);
|
2018-01-06 21:22:22 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString getDropConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
|
|
|
|
|
{
|
2018-11-18 19:30:45 +01:00
|
|
|
|
const PgClass *cls = catalog.classes()->getByKey(constraint.relid);
|
2018-11-30 18:41:38 +01:00
|
|
|
|
return genAlterTable(catalog, *cls) % " DROP CONSTRAINT " % quoteIdent(constraint.objectName()) % ";";
|
2018-01-06 21:22:22 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Helper class that builds comma seperated identifier list
|
|
|
|
|
|
class IdentListString {
|
|
|
|
|
|
public:
|
|
|
|
|
|
void add(QString ident)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_str.isEmpty())
|
|
|
|
|
|
m_str += ",";
|
|
|
|
|
|
m_str += quoteIdent(ident);
|
|
|
|
|
|
}
|
|
|
|
|
|
const QString& str() const { return m_str; }
|
|
|
|
|
|
private:
|
|
|
|
|
|
QString m_str;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2018-02-05 21:42:54 +01:00
|
|
|
|
QString getColumnNameList(const PgDatabaseCatalog &catalog, Oid relid, const SmallAttNumVec<5> &attnums)
|
2018-01-06 21:22:22 +01:00
|
|
|
|
{
|
|
|
|
|
|
IdentListString result;
|
|
|
|
|
|
|
|
|
|
|
|
const auto ac = catalog.attributes();
|
|
|
|
|
|
for (auto an : attnums) {
|
2018-11-18 19:30:45 +01:00
|
|
|
|
result.add(ac->getByKey({ relid, an })->name);
|
2018-01-06 21:22:22 +01:00
|
|
|
|
}
|
|
|
|
|
|
return result.str();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-01 07:09:18 +01:00
|
|
|
|
QString getForeignKeyConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint, const QString &indent)
|
2018-01-06 21:22:22 +01:00
|
|
|
|
{
|
|
|
|
|
|
//PgClass cls = catalog.classes()->getByKey(constraint.relid);
|
2018-11-18 19:30:45 +01:00
|
|
|
|
const PgClass *fcls = catalog.classes()->getByKey(constraint.frelid);
|
2018-01-06 21:22:22 +01:00
|
|
|
|
QString deferrable;
|
|
|
|
|
|
QString validated;
|
|
|
|
|
|
if (!constraint.validated)
|
|
|
|
|
|
validated += " NOT VALID";
|
|
|
|
|
|
if (constraint.deferrable) {
|
|
|
|
|
|
deferrable = QLatin1String(" DEFERRABLE INITIALLY ") % (constraint.deferred ? "DEFERRED" : "IMMEDIATE");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-01 07:09:18 +01:00
|
|
|
|
return "\n" + indent + "FOREIGN KEY ("
|
|
|
|
|
|
% getColumnNameList(catalog, constraint.relid, constraint.key) % ")\n" + indent + "REFERENCES "
|
2018-11-25 19:45:06 +01:00
|
|
|
|
% fcls->fullyQualifiedQuotedObjectName() % " ("
|
2019-12-01 07:09:18 +01:00
|
|
|
|
% getColumnNameList(catalog, constraint.frelid, constraint.fkey) % ")\n" + indent + "MATCH "
|
2018-01-06 21:22:22 +01:00
|
|
|
|
% ForeignKeyMatchToString(constraint.fmatchtype)
|
|
|
|
|
|
% " ON UPDATE " % ForeignKeyActionToString(constraint.fupdtype)
|
|
|
|
|
|
% " ON DELETE " % ForeignKeyActionToString(constraint.fdeltype)
|
2018-12-03 21:03:49 +01:00
|
|
|
|
% deferrable % validated;
|
2018-11-10 13:36:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString getForeignKeyConstraintReferences(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
|
|
|
|
|
{
|
2018-11-18 19:30:45 +01:00
|
|
|
|
const PgClass *fcls = catalog.classes()->getByKey(constraint.frelid);
|
2018-11-10 13:36:36 +01:00
|
|
|
|
QString deferrable;
|
|
|
|
|
|
QString validated;
|
|
|
|
|
|
if (!constraint.validated)
|
|
|
|
|
|
validated += " NOT VALID";
|
|
|
|
|
|
if (constraint.deferrable) {
|
|
|
|
|
|
deferrable = QLatin1String(" DEFERRABLE INITIALLY ") % (constraint.deferred ? "DEFERRED" : "IMMEDIATE");
|
|
|
|
|
|
}
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
2018-11-10 13:36:36 +01:00
|
|
|
|
return "REFERENCES "
|
2018-11-25 19:45:06 +01:00
|
|
|
|
% fcls->fullyQualifiedQuotedObjectName() % " ("
|
2018-11-10 13:36:36 +01:00
|
|
|
|
% getColumnNameList(catalog, constraint.frelid, constraint.fkey) % ") MATCH "
|
|
|
|
|
|
% ForeignKeyMatchToString(constraint.fmatchtype)
|
|
|
|
|
|
% " ON UPDATE " % ForeignKeyActionToString(constraint.fupdtype)
|
|
|
|
|
|
% " ON DELETE " % ForeignKeyActionToString(constraint.fdeltype)
|
|
|
|
|
|
% deferrable % validated;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QString getForeignKeyConstraintReferencesShort(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
|
|
|
|
|
{
|
2018-11-18 19:30:45 +01:00
|
|
|
|
const PgClass *fcls = catalog.classes()->getByKey(constraint.frelid);
|
2018-11-10 13:36:36 +01:00
|
|
|
|
QString deferrable;
|
|
|
|
|
|
QString validated;
|
|
|
|
|
|
if (!constraint.validated)
|
|
|
|
|
|
validated += " NOT VALID";
|
|
|
|
|
|
if (constraint.deferrable) {
|
|
|
|
|
|
deferrable = QLatin1String(" DEFERRABLE") % (constraint.deferred ? " INITIALLY DEFERRED" : "");
|
|
|
|
|
|
}
|
|
|
|
|
|
QString on_update = constraint.fupdtype == ForeignKeyAction::NoAction ? QString() : " ON UPDATE " % ForeignKeyActionToString(constraint.fupdtype);
|
|
|
|
|
|
QString on_delete = constraint.fdeltype == ForeignKeyAction::NoAction ? QString() : " ON DELETE " % ForeignKeyActionToString(constraint.fdeltype);
|
|
|
|
|
|
QString match_type = constraint.fmatchtype == ForeignKeyMatch::Simple ? QString() : " MATCH " % ForeignKeyMatchToString(constraint.fmatchtype);
|
|
|
|
|
|
|
2018-11-25 19:45:06 +01:00
|
|
|
|
return fcls->fullyQualifiedQuotedObjectName() % " ("
|
2018-11-10 13:36:36 +01:00
|
|
|
|
% getColumnNameList(catalog, constraint.frelid, constraint.fkey) % ")"
|
|
|
|
|
|
% match_type
|
|
|
|
|
|
% on_update
|
|
|
|
|
|
% on_delete
|
|
|
|
|
|
% deferrable % validated;
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString getPrimaryKeyConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString ddl = " PRIMARY KEY ("
|
2018-11-30 18:41:38 +01:00
|
|
|
|
% getColumnNameList(catalog, constraint.relid, constraint.key) % ")";
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
|
|
|
|
|
return ddl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString getUniqueConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString ddl = " UNIQUE ("
|
2018-11-30 18:41:38 +01:00
|
|
|
|
% getColumnNameList(catalog, constraint.relid, constraint.key) % ")";
|
2018-01-06 21:22:22 +01:00
|
|
|
|
|
|
|
|
|
|
return ddl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-30 18:41:38 +01:00
|
|
|
|
QString getAlterTableConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
2018-01-06 21:22:22 +01:00
|
|
|
|
{
|
2018-11-18 19:30:45 +01:00
|
|
|
|
const PgClass *cls = catalog.classes()->getByKey(constraint.relid);
|
2018-11-30 18:41:38 +01:00
|
|
|
|
QString result = genAlterTable(catalog, *cls) % "\n ADD ";
|
2019-12-01 07:09:18 +01:00
|
|
|
|
result += getConstraintDefinition(catalog, constraint, " ") % ";";
|
2018-11-30 18:41:38 +01:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-01 07:09:18 +01:00
|
|
|
|
QString getConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint, const QString &indent)
|
2018-11-30 18:41:38 +01:00
|
|
|
|
{
|
|
|
|
|
|
QString result = "CONSTRAINT " % quoteIdent(constraint.objectName());
|
2018-01-06 21:22:22 +01:00
|
|
|
|
switch (constraint.type) {
|
|
|
|
|
|
case ConstraintType::ForeignKey:
|
2019-12-01 07:09:18 +01:00
|
|
|
|
result += getForeignKeyConstraintDefinition(catalog, constraint, indent);
|
2018-01-06 21:22:22 +01:00
|
|
|
|
break;
|
|
|
|
|
|
case ConstraintType::PrimaryKey:
|
|
|
|
|
|
result += getPrimaryKeyConstraintDefinition(catalog, constraint);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ConstraintType::Unique:
|
|
|
|
|
|
result += getUniqueConstraintDefinition(catalog, constraint);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ConstraintType::Check:
|
|
|
|
|
|
default:
|
|
|
|
|
|
result = result % " " % constraint.definition;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|