/*
*
* ProLinga-Data
*
* Copyright (C) 2002-2009 Xobas Software.
* All rights reserved.
*
* This file is part of ProLinga-Data.
*
* ProLinga-Data is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProLinga-Data is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProLinga-Data. If not, see .
*
* More information is available at the following addresses:
*
* Website : http://www.prolinga.org
*
* Email : prolinga-list@prolinga.org
*
*
*/
#include "DatCommon.h"
#include
#include
#include
#include
#include "DatMain.hpp"
#include "DCManageData.hpp"
#include "ExecuteSql.hpp"
#include "DCSession.hpp"
#include "DatConfig.hpp"
extern DCSessionPtr sesPtr;
bool isPrimaryKeyField (const xmlDocPtr docObj, const char *colName)
{
xmlXPathContextPtr ctxObj;
xmlXPathObjectPtr resObj;
int i, j, idxHits, keyHits;
char *idxPrimary, *keyName, tmpString[255];
/* Create XPath Environment */
ctxObj = xmlXPathNewContext(docObj);
/* Get the index values */
resObj = xmlXPathEval((const xmlChar *)"count(/ProLinga/Object/IndexInstances/IndexInstance)", ctxObj);
idxHits = (int)xmlXPathCastToNumber(resObj);
/* Get index Values */
for (i = 1; i<= idxHits; i++)
{
/* Skip non-primary key as this one is created during create table */
sprintf(tmpString, "/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/@Primary", i);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
idxPrimary = (char *)xmlXPathCastToString(resObj);
if (strcmp(idxPrimary, "True") != 0)
continue;
/* Get the key values */
sprintf(tmpString, "count(/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/KeyInstances/KeyInstance)", i);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
keyHits = (int)xmlXPathCastToNumber(resObj);
/* Get index Values */
for (j = 1; j<= keyHits; j++)
{
/* Name */
sprintf(tmpString, "/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/KeyInstances/KeyInstance[@SequenceNo='%d']/@Name", i,j);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
keyName = (char *)xmlXPathCastToString(resObj);
/* Check if name matches */
if (strcmp(colName, keyName) == 0)
return true;
}
}
/* Return */
return false;
}
int DCManageData(const xmlDocPtr docObj, const char *sessionId, char **externalError, xmlDocPtr *docReturn)
{
xmlXPathContextPtr ctxObj;
xmlXPathObjectPtr resObj;
GdaConnection *connection;
char *extTableName;
gchar *extTableNameQuoted;
char *objDataSource = NULL, *objTable = NULL, *buildOption = NULL, *ddType;
char *idxPrimary, *idxName, *idxUnique, *nameTblIdx, *colName;
char *keyName;
char *ddAllowNulls, tmpString[255];
int i, j, k, dbstatus = 0, dataHits, idxHits, keyHits, length;
glong size, decimals;
GdaServerProvider *prov;
GdaServerOperation *op;
const gchar *dbms_type;
GdaMetaContext mcontext = {"_tables", 1, NULL, NULL};
gboolean metaStoreUpdateOK;
GError *error = NULL;
/* Create XPath Environment */
ctxObj = xmlXPathNewContext(docObj);
/* Get DataSource name */
resObj = xmlXPathEval((const xmlChar *)"/ProLinga/Object/@DataSource", ctxObj);
objDataSource = (char *)xmlXPathCastToString(resObj);
/* Get Table name */
resObj = xmlXPathEval((const xmlChar *)"/ProLinga/Object/@Table", ctxObj);
objTable = (char *)xmlXPathCastToString(resObj);
/* Get Build Option */
resObj = xmlXPathEval((const xmlChar *)"/ProLinga/Object/ManageData/@Option", ctxObj);
buildOption = (char *)xmlXPathCastToString(resObj);
/* Get Connection Object to Data Source */
connection = sesPtr->getGdaConnection(sesPtr, sessionId, objDataSource);
if (connection == NULL)
return 70002;
/* Check Option */
if (strcmp(buildOption, "Create") == 0)
{
/* Get DBMS Provider */
prov = gda_connection_get_provider(connection);
if (!prov)
return 70023;
/* Get external (= table to build) table name */
resObj = xmlXPathEval((const xmlChar *)"/ProLinga/Object/ManageData/ExternalTableName", ctxObj);
extTableName = (char *)xmlXPathCastToString(resObj);
/* Drop Table */
op = gda_server_provider_create_operation (prov, connection, GDA_SERVER_OPERATION_DROP_TABLE, NULL, &error);
if (!op)
{
if (error)
{
*externalError = error->message;
return 90001;
}
else
return 70022;
}
else
{
/* we have to set the table name parameter */
if (!gda_server_operation_set_value_at(op, extTableName, NULL, "/TABLE_DESC_P/TABLE_NAME"))
{
g_object_unref (op);
return 70022;
}
else
{
/* Drop table and ignore error output. If there is nothing to drop, that is OK */
gda_connection_perform_operation(connection, op, NULL);
}
g_object_unref (op);
}
/* Prepare to create the table */
op = gda_server_provider_create_operation (prov, connection, GDA_SERVER_OPERATION_CREATE_TABLE, NULL, &error);
if (!op)
{
if (error)
{
*externalError = error->message;
return 90001;
}
else
return 70023;
}
/* Get the data values */
resObj = xmlXPathEval((const xmlChar *)"count(/ProLinga/Object/DataInstances/DataInstance)", ctxObj);
dataHits = (int)xmlXPathCastToNumber(resObj);
/* Set Table Name */
if (!gda_server_operation_set_value_at (op, extTableName, NULL, "/TABLE_DEF_P/TABLE_NAME"))
{
g_object_unref (op);
return 70023;
}
/* Get data Values (Columns) */
for (i = 0; i<= (dataHits-1); i++)
{
/* Set XML Doc idx */
j = i+1;
/* Column Name */
sprintf(tmpString, "/ProLinga/Object/DataInstances/DataInstance[@SequenceNo='%d']/@Name", j);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
colName = (char *)xmlXPathCastToString(resObj);
if (!gda_server_operation_set_value_at (op, colName, NULL, "/FIELDS_A/@COLUMN_NAME/%d", i))
{
g_object_unref (op);
return 70023;
}
/* Size */
sprintf(tmpString, "/ProLinga/Object/DataInstances/DataInstance[@SequenceNo='%d']/@Size", j);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
size = (glong)xmlXPathCastToNumber(resObj);
/* Decimals */
sprintf(tmpString, "/ProLinga/Object/DataInstances/DataInstance[@SequenceNo='%d']/@Decimals", j);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
decimals = (glong)xmlXPathCastToNumber(resObj);
/* Storage Type */
sprintf(tmpString, "/ProLinga/Object/DataInstances/DataInstance[@SequenceNo='%d']/@StorageType", j);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
ddType = (char *)xmlXPathCastToString(resObj);
if (strcmp(ddType, "Character") == 0)
dbms_type = gda_server_provider_get_default_dbms_type(prov,connection,G_TYPE_STRING);
else if (strcmp(ddType, "Integer") == 0)
dbms_type = gda_server_provider_get_default_dbms_type(prov,connection,G_TYPE_INT);
else if (strcmp(ddType, "Long") == 0)
dbms_type = gda_server_provider_get_default_dbms_type(prov,connection,G_TYPE_INT64);
else if (strcmp(ddType, "Single") == 0)
dbms_type = gda_server_provider_get_default_dbms_type(prov,connection,G_TYPE_FLOAT);
else if (strcmp(ddType, "Double") == 0)
dbms_type = gda_server_provider_get_default_dbms_type(prov,connection,G_TYPE_DOUBLE);
else if (strcmp(ddType, "Numeric") == 0)
dbms_type = gda_server_provider_get_default_dbms_type(prov,connection,GDA_TYPE_NUMERIC);
else if (strcmp(ddType, "Date") == 0)
dbms_type = gda_server_provider_get_default_dbms_type(prov,connection,G_TYPE_DATE);
else
{
g_object_unref (op);
return 70018;
}
if (!gda_server_operation_set_value_at (op, dbms_type, NULL, "/FIELDS_A/@COLUMN_TYPE/%d", i))
{
g_object_unref (op);
return 70023;
}
/* Size */
if ((strcmp(ddType, "Numeric") == 0) || (strcmp(ddType, "Character") == 0))
{
sprintf(tmpString, "%ld", size);
if (!gda_server_operation_set_value_at (op, tmpString, NULL, "/FIELDS_A/@COLUMN_SIZE/%d", i))
{
g_object_unref (op);
return 70023;
}
}
/* Scale */
if (strcmp(ddType, "Numeric") == 0)
{
sprintf(tmpString, "%ld", decimals);
if (!gda_server_operation_set_value_at (op, tmpString, NULL, "/FIELDS_A/@COLUMN_SCALE/%d", i))
{
g_object_unref (op);
return 70023;
}
}
/* AllowNulls */
sprintf(tmpString, "/ProLinga/Object/DataInstances/DataInstance[@SequenceNo='%d']/@AllowNulls", j);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
ddAllowNulls = (char *)xmlXPathCastToString(resObj);
if (strcmp(ddAllowNulls,"True") == 0)
{
if (!gda_server_operation_set_value_at (op, "TRUE", NULL, "/FIELDS_A/@COLUMN_NNUL/%d", i))
{
g_object_unref (op);
return 70023;
}
}
else
{
if (!gda_server_operation_set_value_at (op, "FALSE", NULL, "/FIELDS_A/@COLUMN_NNUL/%d", i))
{
g_object_unref (op);
return 70023;
}
}
/* Set Primary and Unique to FALSE */
if (!gda_server_operation_set_value_at (op, "FALSE", NULL, "/FIELDS_A/@COLUMN_UNIQUE/%d", i))
{
g_object_unref (op);
return 70023;
}
/* Check if column name part of primary key */
if (isPrimaryKeyField(docObj, colName) == true)
{
if (!gda_server_operation_set_value_at (op, "TRUE", NULL, "/FIELDS_A/@COLUMN_PKEY/%d", i))
{
g_object_unref (op);
return 70023;
}
}
else
{
if (!gda_server_operation_set_value_at (op, "FALSE", NULL, "/FIELDS_A/@COLUMN_PKEY/%d", i))
{
g_object_unref (op);
return 70023;
}
}
}
/* Call create table call */
if (! gda_server_provider_perform_operation(prov, connection, op, &error))
{
if (error)
{
*externalError = error->message;
g_object_unref (op);
return 90001;
}
else
{
g_object_unref (op);
return 70023;
}
}
g_object_unref (op);
/* Create Indexes */
/* Get the index values */
resObj = xmlXPathEval((const xmlChar *)"count(/ProLinga/Object/IndexInstances/IndexInstance)", ctxObj);
idxHits = (int)xmlXPathCastToNumber(resObj);
/* Get index Values */
for (i = 1; i<= idxHits; i++)
{
/* Skip primary key as this one is created during create table */
sprintf(tmpString, "/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/@Primary", i);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
idxPrimary = (char *)xmlXPathCastToString(resObj);
if (strcmp(idxPrimary, "True") == 0)
continue;
/* Name */
sprintf(tmpString, "/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/@Name", i);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
idxName = (char *)xmlXPathCastToString(resObj);
length = strlen(extTableName) + strlen(idxName) + 1;
nameTblIdx = new char[(length+1)];
strcpy(nameTblIdx, extTableName);
strcat(nameTblIdx, "_");
strcat(nameTblIdx, idxName);
/* Drop Index */
op = gda_server_provider_create_operation (prov, connection, GDA_SERVER_OPERATION_DROP_INDEX, NULL, NULL);
if (op)
{
if (!gda_server_operation_set_value_at (op, nameTblIdx, NULL, "/INDEX_DESC_P/INDEX_NAME"))
{
delete nameTblIdx;
g_object_unref (op);
return 70024;
}
if (!gda_server_operation_set_value_at (op, extTableName, NULL, "/INDEX_DESC_P/INDEX_ON_TABLE"))
{
delete nameTblIdx;
g_object_unref (op);
return 70024;
}
/* Remove index and ignore output as we don't care if the index was really there */
gda_server_provider_perform_operation(prov, connection, op, NULL);
/* Clean up */
g_object_unref (op);
}
/* Prepare to create the index */
op = gda_server_provider_create_operation (prov, connection, GDA_SERVER_OPERATION_CREATE_INDEX, NULL, NULL);
if (!op)
{
if (error)
{
*externalError = error->message;
delete nameTblIdx;
g_object_unref (op);
return 90001;
}
else
{
delete nameTblIdx;
g_object_unref (op);
return 70025;
}
}
if (!gda_server_operation_set_value_at (op, nameTblIdx, NULL, "/INDEX_DEF_P/INDEX_NAME"))
{
delete nameTblIdx;
g_object_unref (op);
return 70025;
}
/* Unique */
sprintf(tmpString, "/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/@Unique", i);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
idxUnique = (char *)xmlXPathCastToString(resObj);
if (strcmp(idxUnique, "True") == 0)
{
if (!gda_server_operation_set_value_at (op, "UNIQUE", NULL, "/INDEX_DEF_P/INDEX_TYPE"))
{
delete nameTblIdx;
g_object_unref (op);
return 70025;
}
}
else
{
if (!gda_server_operation_set_value_at (op, "", NULL, "/INDEX_DEF_P/INDEX_TYPE"))
{
delete nameTblIdx;
g_object_unref (op);
return 70025;
}
}
if (!gda_server_operation_set_value_at (op, extTableName, NULL, "/INDEX_DEF_P/INDEX_ON_TABLE"))
{
delete nameTblIdx;
g_object_unref (op);
return 70025;
}
/* Get the key values */
sprintf(tmpString, "count(/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/KeyInstances/KeyInstance)", i);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
keyHits = (int)xmlXPathCastToNumber(resObj);
/* Get index Values */
for (k = 0; k<= (keyHits-1); k++)
{
/* Set XML Doc idx */
j = k+1;
/* Name */
sprintf(tmpString, "/ProLinga/Object/IndexInstances/IndexInstance[@SequenceNo='%d']/KeyInstances/KeyInstance[@SequenceNo='%d']/@Name", i,j);
resObj = xmlXPathEval((const xmlChar *)tmpString, ctxObj);
keyName = (char *)xmlXPathCastToString(resObj);
if (!gda_server_operation_set_value_at (op, keyName, NULL, "/INDEX_FIELDS_S/%d/INDEX_FIELD", k))
{
delete nameTblIdx;
g_object_unref (op);
return 70025;
}
}
/* Call create index call */
if (! gda_server_provider_perform_operation(prov, connection, op, &error))
{
if (error)
{
*externalError = error->message;
delete nameTblIdx;
g_object_unref (op);
return 90001;
}
else
{
delete nameTblIdx;
g_object_unref (op);
return 70025;
}
}
/* Clean up */
g_object_unref (op);
delete nameTblIdx;
}
/* Update Meta Store */
mcontext.column_names = g_new (gchar *, 1);
mcontext.column_names[0] = "table_name";
mcontext.column_values = g_new (GValue *, 1);
extTableNameQuoted = gda_sql_identifier_quote(extTableName, connection, NULL, TRUE, FALSE);
g_value_set_string ((mcontext.column_values[0] = gda_value_new(G_TYPE_STRING)), extTableNameQuoted);
g_free(extTableNameQuoted);
metaStoreUpdateOK = gda_connection_update_meta_store(connection, &mcontext, &error);
gda_value_free (mcontext.column_values[0]);
if (metaStoreUpdateOK == FALSE)
{
*externalError = error->message;
return 90001;
}
}
else if (strcmp(buildOption, "Drop") == 0)
{
/* Get external (= table to build) table name */
resObj = xmlXPathEval((const xmlChar *)"/ProLinga/Object/ManageData/ExternalTableName", ctxObj);
extTableName = (char *)xmlXPathCastToString(resObj);
/* Drop Table */
op = gda_connection_create_operation(connection,GDA_SERVER_OPERATION_DROP_TABLE, NULL, &error);
if (!op)
{
if (error)
{
*externalError = error->message;
return 90001;
}
else
return 70024;
}
else
{
/* we have to set the table name parameter */
if (!gda_server_operation_set_value_at(op, extTableName, NULL, "/TABLE_DESC_P/TABLE_NAME"))
{
g_object_unref (op);
return 70024;
}
else
{
if(!gda_connection_perform_operation(connection, op, NULL))
{
g_object_unref (op);
return 70024;
}
/* Update Meta Store */
mcontext.column_names = g_new (gchar *, 1);
mcontext.column_names[0] = "table_name";
mcontext.column_values = g_new (GValue *, 1);
extTableNameQuoted = gda_sql_identifier_quote(extTableName, connection, NULL, TRUE, FALSE);
g_value_set_string ((mcontext.column_values[0] = gda_value_new(G_TYPE_STRING)), extTableNameQuoted);
g_free(extTableNameQuoted);
metaStoreUpdateOK = gda_connection_update_meta_store(connection, &mcontext, &error);
gda_value_free (mcontext.column_values[0]);
if (metaStoreUpdateOK == FALSE)
{
*externalError = error->message;
return 90001;
}
}
g_object_unref (op);
}
}
else
return 70013;
/* Create return document */
*docReturn = xmlNewDoc((const xmlChar *)XML_VERSION);
(*docReturn)->children = xmlNewDocNode(*docReturn, NULL, (const xmlChar *)ROOT_ELEM, NULL);
/* Return */
return dbstatus;
}