Improved code generation for functions and procedures.

alter statements for configuration settings
alter statement for owner
This commit is contained in:
eelke 2018-12-23 19:45:04 +01:00
parent fc58acb252
commit 54d4dfface
5 changed files with 145 additions and 69 deletions

View file

@ -30,7 +30,4 @@ const PgDatabaseCatalog& PgObject::catalog() const
return *m_catalog;
}
void test(PgObject a, PgObject b)
{
a = b;
}

View file

@ -2,6 +2,7 @@
#include "PgAuthId.h"
#include "PgAuthIdContainer.h"
#include "PgDatabaseCatalog.h"
#include "SqlFormattingUtils.h"
void PgOwnedObject::setOwnerOid(PgDatabaseCatalog& cat, Oid oid)
{
@ -23,3 +24,9 @@ const PgAuthId* PgOwnedObject::owner() const
{
return m_owner;
}
QString PgOwnedObject::alterOwnerSql(const QString& ident) const
{
return QString("\nALTER %1 OWNER TO %2;").arg(ident, quoteIdent(ownerName()));
}

View file

@ -14,6 +14,8 @@ public:
Oid ownerOid() const;
QString ownerName() const;
const PgAuthId* owner() const;
QString alterOwnerSql(const QString& ident) const;
private:
Oid m_ownerOid = InvalidOid;
const PgAuthId * m_owner;

View file

@ -91,9 +91,44 @@ void operator<<(ProcKind &s, const Pgsql::Value &v)
case 'w':
s = ProcKind::Window;
break;
default:
throw std::runtime_error("Unexpected value for ProcKind");
}
}
void operator<<(ParallelMode &s, const Pgsql::Value &v)
{
const char *c = v.c_str();
switch (*c) {
case 'u':
s = ParallelMode::Unsafe;
break;
case 'r':
s = ParallelMode::Restricted;
break;
case 's':
s = ParallelMode::Safe;
break;
default:
throw std::runtime_error("Unexpected value for ParallelMode");
}
}
QString parallelModeToSql(ParallelMode pm, bool explicit_unsafe)
{
switch (pm) {
case ParallelMode::Unsafe:
return explicit_unsafe ? "PARALLEL UNSAFE" : "";
case ParallelMode::Restricted:
return "PARALLEL RESTRICTED";
case ParallelMode::Safe:
return "PARALLEL SAFE";
default:
throw std::runtime_error("Unexpected value for pm in parallelModeToSql");
}
}
void PgProc::setArgs(
std::vector<Oid> argtypes,
std::vector<Oid> allargtypes,
@ -210,89 +245,106 @@ QString PgProc::argSigList(const bool forScript) const
}
QString PgProc::createSql() const
const QString& PgProc::createSql() const
{
if (createSqlCache.isEmpty()) {
QString sql;
//wxString qtName = GetQuotedFullIdentifier() + wxT("(") + GetArgListWithNames(true) + wxT(")");
if (isAggregate()) {
/// \todo Support for aggregates
createSqlCache = "-- aggregates not supported yet\n";
return createSqlCache;
}
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());
if (isProcedure()) {
// P CREATE [ OR REPLACE ] PROCEDURE
// name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
sql = QString("-- Procedure: %1\n\n"
"-- DROP PROCEDURE %1;\n\n"
"CREATE OR REPLACE PROCEDURE %2\n"
).arg(quoted_sig, quoted_name);
}
else {
// all other kinds are functions
// F CREATE [ OR REPLACE ] FUNCTION
// name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
// F [ RETURNS rettype
/// \todo F | RETURNS TABLE ( column_name column_type [, ...] ) ]
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"
" RETURNS %3"
).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());
// else
// sql += qtDbString(GetSource());
// }
QString language;
{
auto l = catalog().languages()->getByKey(lang);
if (l)
language = l->objectName();
}
if (language == "c") {
sql += " AS\n";
auto language = catalog().languages()->getByKey(lang);
BOOST_ASSERT(language != nullptr);
if (language->isC()) {
// | AS 'obj_file', 'link_symbol'
sql += escapeLiteral(bin) % ", " % escapeLiteral(src);
}
else {
// | AS 'definition'
sql += dollarQuoteString(src);
}
// sql += wxT("\n LANGUAGE ") + GetLanguage() + wxT(" ");
sql += "\n LANGUAGE " % language % " ";
// if (GetConnection()->BackendMinimumVersion(8, 4) && GetIsWindow())
// sql += wxT("WINDOW ");
if (isWindow())
sql += "WINDOW ";
// sql += GetVolatility();
sql += volatility();
// { LANGUAGE lang_name
sql += "\n LANGUAGE " % language->quotedObjectName();
/// \todo | TRANSFORM { FOR TYPE type_name } [, ... ]
// | WINDOW
if (isWindow())
sql += " WINDOW";
if (!isProcedure()) {
// F | IMMUTABLE | STABLE | VOLATILE | [ NOT ] LEAKPROOF
sql += " " % volatility();
if (leakproof)
sql += " LEAKPROOF";
// F | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
// CALLED ON NULL INPUT is the default so we never specify this
// RETURNS NULL ON NULL INPUT is an alias for STRICT so we use STRICT
if (isstrict)
sql += " STRICT";
// if (GetSecureDefiner())
// sql += wxT(" SECURITY DEFINER");
sql += QString("\n COST %1").arg(cost);
sql += " STRICT"
;
/// \todo F | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
// if (GetSecureDefiner())
// sql += wxT(" SECURITY DEFINER");
// F | PARALLEL { UNSAFE | RESTRICTED | SAFE }
sql += " " % parallelModeToSql(parallel);
// F | COST execution_cost
sql += QString("\n COST %1").arg(static_cast<double>(cost));
// F | ROWS result_rows
if (retset)
sql += QString("n ROWS %1").arg(rows);
sql += ";";
// if (!sql.Strip(wxString::both).EndsWith(wxT(";")))
// sql += wxT(";");
sql += QString("n ROWS %1").arg(static_cast<double>(rows));
// 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 += ";";
// | SET configuration_parameter { TO value | = value | FROM CURRENT }
for (auto&& cfg : config) {
auto before = cfg.section('=', 0, 0); // before first =
auto after = cfg.section('=', 1, -1); // everything after first =
if (before != "search_path" && before != "temp_tablespaces")
sql += QString("\nALTER FUNCTION %1 SET %2 TO '%3'").arg(quoted_sig, before, after);
else
sql += QString("\nALTER FUNCTION %1 SET %2 TO %3").arg(quoted_sig, before, after);
}
// sql += wxT("\n")
// + GetOwnerSql(8, 0, wxT("FUNCTION ") + qtSig)
// + GetGrant(wxT("X"), wxT("FUNCTION ") + qtSig);
sql += alterOwnerSql("FUNCTION " + quoted_sig);
// if (!GetComment().IsNull())
// {
// sql += wxT("COMMENT ON FUNCTION ") + qtSig

View file

@ -34,6 +34,24 @@ enum class ProcKind {
void operator<<(ProcKind &s, const Pgsql::Value &v);
enum class ParallelMode {
Unsafe, // u, default
Restricted, // r,
Safe // s
};
void operator<<(ParallelMode &s, const Pgsql::Value &v);
/**
* @brief parallelModeToSql
* @param pm The parallel mode
* @param explicit_unsafe When false an empty string is return for unsage when true
* a "PARALLEL UNSAFE" is returned.
* @return
*/
QString parallelModeToSql(ParallelMode pm, bool explicit_unsafe = false);
class PgProc: public PgNamespaceObject, public PgOwnedObject {
public:
using PgNamespaceObject::PgNamespaceObject;
@ -55,7 +73,7 @@ public:
bool isstrict = false; // bool
bool retset = false; // bool
char provolatile = '\0'; // char
char parallel = '\0'; // char, version >= 9.6
ParallelMode parallel = ParallelMode::Unsafe; // char, version >= 9.6
int16_t nargs = 0; // int2
int16_t nargdefaults; // = 0; // int2
Oid rettype = InvalidOid; // oid
@ -81,7 +99,7 @@ public:
// bool operator<(Oid _oid) const { return oid < _oid; }
// bool operator<(const PgProc &rhs) const { return oid < rhs.oid; }
QString createSql() const;
const QString& createSql() const;
QString argListWithNames(bool multiline = false) const;
QString argSigList(const bool forScript = false) const;