#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,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";
	if (minimumVersion(110000))
		column_list += ",prokind";
	else
		column_list += ",proisagg,proiswindow";

	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();
	Oid owner_oid = col.nextValue();

	//ProcKind

	PgProc v(m_catalog, oid, name, namespace_oid);
	v.setOwnerOid(owner_oid);
	col  >> v.lang >> v.cost >> v.rows
			>> v.variadic >> 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;
	AclList acl_list;
	col >> acl_list;
	v.setAcls(std::move(acl_list));
	v.setArgs(argtypes, allargtypes, argmodes, argnames, argdefaults);

	if (minimumVersion(90500)) {
		col >> v.trftypes;
	}
	if (minimumVersion(90600)) {
		col >> v.parallel;
	}
	if (minimumVersion(110000))
		col >> v.kind;
	else {
		bool agg, window;
		col >> agg >> window;
		if (agg)
			v.kind = ProcKind::Aggregate;
		else if (window)
			v.kind = ProcKind::Window;
		else {
			v.kind = ProcKind::Function;
		}
		// Only 11 and higher has ProcKind::Procedure!
	}

	return v;
}
