//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
// RCS-ID:      $Id:  $
// Copyright (C) 2002 - 2009, The pgAdmin Development Team
// This software is released under the Artistic Licence
//
// gpPartition.cpp - Greenplum Table Partition class
//
//////////////////////////////////////////////////////////////////////////

#include "pgAdmin3.h"


#include "utils/misc.h"
#include "frm/frmHint.h"
#include "frm/frmMain.h"
#include "frm/frmMaintenance.h"
#include "schema/pgTable.h"
#include "schema/gpPartition.h"
#include "schema/pgColumn.h"
#include "schema/pgIndexConstraint.h"
#include "schema/pgForeignKey.h"
#include "schema/pgCheck.h"
#include "utils/sysSettings.h"
#include "utils/pgfeatures.h"
#include "schema/pgRule.h"
#include "schema/pgTrigger.h"
#include "schema/pgConstraints.h"


// App headers

gpPartition::gpPartition(pgSchema *newSchema, const wxString& newName)
: pgTable(newSchema, newName)
{
}

gpPartition::~gpPartition()
{
}

 
wxString gpPartition::GetSql(ctlTree *browser)
{
	wxString sql;
	sql = wxT("-- This DDL is just a representation of how the partition might look as a table\n");
	sql += wxT("-- You don't use CREATE TABLE to create partitions, you use ALTER TABLE\n");
	sql += wxT("-- or create them as part of the base table's CREATE TABLE\n\n");
	sql += pgTable::GetSql(browser);
	return sql;
}

///////////////////////////////////////////////////////////

gpPartitionCollection::gpPartitionCollection(pgaFactory *factory, gpPartition *_table)
: pgTableCollection(factory, _table->GetSchema()) { iSetOid(_table->GetOid()); }


pgObject *gpPartitionFactory::CreateObjects(pgCollection *coll, ctlTree *browser, const wxString &restriction)
{
	gpPartitionCollection *collection=(gpPartitionCollection*)coll;
    wxString query;
    gpPartition *table=0;

	pgSet *tables;

	query= wxT("SELECT rel.oid, relname, rel.reltablespace AS spcoid, spcname, pg_get_userbyid(relowner) AS relowner, relacl, relhasoids, ")
		wxT("relhassubclass, reltuples, description, conname, conkey,\n")
		wxT("       EXISTS(select 1 FROM pg_trigger\n")
		wxT("                       JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'\n")
		wxT("                       JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'\n")
		wxT("                     WHERE tgrelid=rel.oid) AS isrepl\n");

	query += wxT(", substring(array_to_string(reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor \n");
	query += wxT(", gpd.localoid, gpd.attrnums \n");
	query += wxT(", substring(array_to_string(reloptions, ',') from 'appendonly=([a-z]*)') AS appendonly \n");
	query += wxT(", substring(array_to_string(reloptions, ',') from 'compresslevel=([0-9]*)') AS compresslevel \n");
	//query += wxT(", rel.oid in (select parrelid from pg_partition) as ispartitioned\n"); // This only works for top-level tables, not intermediate ones
	// This looks for intermediate partitions that have subpartitions
	query += wxT(", rel.oid in (select pr.parchildrelid from pg_partition_rule pr, pg_partition pp where pr.paroid = pp.oid and pp.parlevel < (select max(parlevel) from pg_partition where parrelid = pp.parrelid)) as ispartitioned \n");


	query += wxT("  FROM pg_class rel JOIN pg_partition_rule pr ON(rel.oid = pr.parchildrelid) JOIN pg_partition p ON (pr.paroid = p.oid)\n")
		wxT("  LEFT OUTER JOIN pg_tablespace ta on ta.oid=rel.reltablespace\n")
		wxT("  LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0)\n")
		wxT("  LEFT OUTER JOIN pg_constraint c ON c.conrelid=rel.oid AND c.contype='p'\n");
	query += wxT("  LEFT OUTER JOIN gp_distribution_policy gpd ON gpd.localoid=rel.oid\n");
	query += wxT(" WHERE relkind = 'r' AND p.parrelid = ") + collection->GetOidStr() + wxT("\n");

	query += restriction + 
		wxT(" ORDER BY relname");


    tables= collection->GetDatabase()->ExecuteSet(query);
    if (tables)
    {
        while (!tables->Eof())
        {
            table = new gpPartition(collection->GetSchema(), tables->GetVal(wxT("relname")));

			table->iSetOid(tables->GetOid(wxT("oid")));
			table->iSetOwner(tables->GetVal(wxT("relowner")));
			table->iSetAcl(tables->GetVal(wxT("relacl")));

			if (tables->GetOid(wxT("spcoid")) == 0)
				table->iSetTablespaceOid(collection->GetDatabase()->GetTablespaceOid());
			else
				table->iSetTablespaceOid(tables->GetOid(wxT("spcoid")));

			if (tables->GetVal(wxT("spcname")) == wxEmptyString)
				table->iSetTablespace(collection->GetDatabase()->GetTablespace());
			else
				table->iSetTablespace(tables->GetVal(wxT("spcname")));

			table->iSetComment(tables->GetVal(wxT("description")));
			table->iSetHasOids(tables->GetBool(wxT("relhasoids")));
			table->iSetEstimatedRows(tables->GetDouble(wxT("reltuples")));

			table->iSetFillFactor(tables->GetVal(wxT("fillfactor")));

			table->iSetHasSubclass(tables->GetBool(wxT("relhassubclass")));
			table->iSetPrimaryKeyName(tables->GetVal(wxT("conname")));
			table->iSetIsReplicated(tables->GetBool(wxT("isrepl")));
			wxString cn=tables->GetVal(wxT("conkey"));
			cn=cn.Mid(1, cn.Length()-2);
			table->iSetPrimaryKeyColNumbers(cn);


			Oid lo=tables->GetOid(wxT("localoid"));
			wxString db=tables->GetVal(wxT("attrnums"));
			db=db.Mid(1, db.Length()-2);
			table->iSetDistributionColNumbers(db);
			if (lo > 0 && db.Length() == 0)
				table->iSetDistributionIsRandom();
			table->iSetAppendOnly(tables->GetVal(wxT("appendonly")));
			table->iSetCompressLevel(tables->GetVal(wxT("compresslevel")));

			table->iSetPartitionDef(wxT(""));
			table->iSetIsPartitioned(tables->GetBool(wxT("ispartitioned"))); 
	
			if (browser)
			{
				browser->AppendObject(collection, table);
				tables->MoveNext();
			}
			else
				break;
		}

		delete tables;
	}
    return table;
}


#include "images/table.xpm"
#include "images/table-repl.xpm"
#include "images/table-repl-sm.xpm"
#include "images/table-sm.xpm"
#include "images/tables.xpm"

gpPartitionFactory::gpPartitionFactory() 
: pgTableObjFactory(__("Partition"), __("New Partition..."), __("Create a new Partition."), table_xpm, table_sm_xpm)
{
    metaType = PGM_TABLE;
}

pgCollection *gpPartitionFactory::CreateCollection(pgObject *obj)
{
    return new gpPartitionCollection(GetCollectionFactory(), (gpPartition *)obj );
}

gpPartitionFactory partitionFactory;
static pgaCollectionFactory cf(&partitionFactory, __("Partitions"), tables_xpm);


