mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-23 07:05:36 +03:00
1293 lines
46 KiB
C++
1293 lines
46 KiB
C++
/* Copyright (C) 2014 InfiniDB, Inc.
|
||
|
||
This program 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; version 2 of
|
||
the License.
|
||
|
||
This program 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 this program; if not, write to the Free Software
|
||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
MA 02110-1301, USA. */
|
||
|
||
/*******************************************************************************
|
||
* $Id: we_xmljob.cpp 4579 2013-03-19 23:16:54Z dhall $
|
||
*
|
||
*******************************************************************************/
|
||
/** @file */
|
||
|
||
#define WRITEENGINEXMLJOB_DLLEXPORT
|
||
#include "we_xmljob.h"
|
||
#undef WRITEENGINEXMLJOB_DLLEXPORT
|
||
|
||
#include <limits>
|
||
#include <sstream>
|
||
#include <unistd.h>
|
||
#include <stdexcept>
|
||
#include <cstdlib>
|
||
#include <set>
|
||
#include "we_config.h"
|
||
#include "we_log.h"
|
||
#include "we_convertor.h"
|
||
#include "dataconvert.h"
|
||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||
#include <boost/filesystem/path.hpp>
|
||
#include <boost/filesystem/convenience.hpp>
|
||
|
||
#include <sys/time.h>
|
||
|
||
using namespace std;
|
||
using namespace execplan;
|
||
|
||
|
||
namespace WriteEngine
|
||
{
|
||
// Maximum saturation value for DECIMAL types based on precision
|
||
const long long infinidb_precision[19] = {
|
||
0,
|
||
9,
|
||
99,
|
||
999,
|
||
9999,
|
||
99999,
|
||
999999,
|
||
9999999,
|
||
99999999,
|
||
999999999,
|
||
9999999999LL,
|
||
99999999999LL,
|
||
999999999999LL,
|
||
9999999999999LL,
|
||
99999999999999LL,
|
||
999999999999999LL,
|
||
9999999999999999LL,
|
||
99999999999999999LL,
|
||
999999999999999999LL
|
||
};
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Constructor
|
||
//------------------------------------------------------------------------------
|
||
XMLJob::XMLJob( ) : fDebugLevel( DEBUG_0 ),
|
||
fDeleteTempFile(false),
|
||
fValidateColList(true)
|
||
{
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Default Destructor
|
||
// Delete temporary Job XML file if applicable.
|
||
//------------------------------------------------------------------------------
|
||
XMLJob::~XMLJob()
|
||
{
|
||
if ((fDeleteTempFile) && (!fJobFileName.empty()))
|
||
{
|
||
unlink( fJobFileName.c_str() );
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Load a job xml file
|
||
// fileName - name of file to load
|
||
// bTempFile - are we loading a temporary file (that destructor should delete)
|
||
// bValidateColumnList - validate that all db columns have an XML tag
|
||
// returns NO_ERROR if success; other if fail
|
||
//------------------------------------------------------------------------------
|
||
int XMLJob::loadJobXmlFile( const string& fileName,
|
||
bool bTempFile,
|
||
bool bValidateColumnList,
|
||
string& errMsg )
|
||
{
|
||
int rc;
|
||
|
||
fDeleteTempFile = bTempFile;
|
||
fJobFileName = fileName;
|
||
fValidateColList= bValidateColumnList;
|
||
|
||
try
|
||
{
|
||
rc = parseDoc( fileName.c_str() );
|
||
if (rc != NO_ERROR)
|
||
return rc;
|
||
}
|
||
catch (exception& ex)
|
||
{
|
||
errMsg = ex.what();
|
||
return ERR_XML_PARSE;
|
||
}
|
||
|
||
return rc;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Print contents of fJob to the specified logger object.
|
||
// logger - Log object to use in logging
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::printJobInfo( Log& logger ) const
|
||
{
|
||
const Job& job = fJob;
|
||
|
||
ostringstream oss1;
|
||
oss1 << "Job " << job.id << " input\n";
|
||
oss1 << "===============================================" << endl;
|
||
oss1 << "Name : " << job.name << endl;
|
||
oss1 << "Desc : " << job.desc << endl;
|
||
oss1 << "User : " << job.userName << endl;
|
||
oss1 << "Delim: " << job.fDelimiter << endl;
|
||
oss1 << "Enclosed By : ";
|
||
if (job.fEnclosedByChar)
|
||
oss1 << job.fEnclosedByChar << endl;
|
||
else
|
||
oss1 << "n/a" << endl;
|
||
oss1 << "Escape Char : ";
|
||
if (job.fEscapeChar)
|
||
oss1 << job.fEscapeChar << endl;
|
||
else
|
||
oss1 << "n/a" << endl;
|
||
oss1 << "Read Buffers: " << job.numberOfReadBuffers << endl;
|
||
oss1 << "Read Buffer Size: " << job.readBufferSize << endl;
|
||
oss1 << "setvbuf Size: " << job.writeBufferSize << endl;
|
||
oss1 << "Create Date : " << job.createDate << endl;
|
||
oss1 << "Create Time : " << job.createTime << endl;
|
||
oss1 << "Schema Name : " << job.schema << endl;
|
||
|
||
oss1 << "Num Tables : " << job.jobTableList.size() << endl;
|
||
logger.logMsg( oss1.str(), MSGLVL_INFO2 );
|
||
|
||
for( unsigned int i = 0; i < job.jobTableList.size(); i++ ) {
|
||
const JobTable& jobTable = job.jobTableList[i];
|
||
ostringstream oss2;
|
||
oss2 << "\n-------------------------------------------------" << endl;
|
||
oss2 << "\tTable Name : " << jobTable.tblName << endl;
|
||
oss2 << "\tTable OID : " << jobTable.mapOid << endl;
|
||
oss2 << "\tTable Load Name : " << jobTable.loadFileName <<
|
||
endl;
|
||
oss2 << "\tMax Err Num : " << jobTable.maxErrNum << endl;
|
||
|
||
const JobColList& colList = jobTable.colList;
|
||
|
||
oss2 << "\tNum of Columns : " << colList.size() << endl;
|
||
logger.logMsg( oss2.str(), MSGLVL_INFO2 );
|
||
|
||
// Note that we don't print JobColumn.dataType because it is not carried
|
||
// in the XML file. dataType is assigned/used internally by bulkload.
|
||
for( unsigned int j = 0; j < jobTable.fFldRefs.size(); j++ ) {
|
||
unsigned idx = jobTable.fFldRefs[j].fArrayIndex;
|
||
BulkFldColRel fldColType= jobTable.fFldRefs[j].fFldColType;
|
||
const JobColumn& jobCol = ((fldColType == BULK_FLDCOL_IGNORE_FIELD)?
|
||
jobTable.fIgnoredFields[idx] :
|
||
jobTable.colList[idx] );
|
||
ostringstream oss3;
|
||
oss3 << "\n\t****************************************" << endl;
|
||
if (fldColType == BULK_FLDCOL_COLUMN_DEFAULT)
|
||
oss3 << "\t\tDefaultColumn Name: " << jobCol.colName << endl;
|
||
else
|
||
oss3 << "\t\tColumn Name : " << jobCol.colName << endl;
|
||
oss3 << "\t\tColumn OID : " << jobCol.mapOid << endl;
|
||
oss3 << "\t\tColumn type name : " << jobCol.typeName << endl;
|
||
oss3 << "\t\tColumn width : " << jobCol.width << endl;
|
||
oss3 << "\t\tColumn Not Null : " << jobCol.fNotNull << endl;
|
||
oss3 << "\t\tColumn WithDefault: " << jobCol.fWithDefault << endl;
|
||
oss3 << "\t\tColumn type : " << jobCol.colType << endl;
|
||
oss3 << "\t\tColumn comp type : " << jobCol.compressionType <<endl;
|
||
oss3 << "\t\tColumn autoInc : " << jobCol.autoIncFlag << endl;
|
||
|
||
if( jobCol.typeName == ColDataTypeStr[CalpontSystemCatalog::DECIMAL] ) {
|
||
oss3 << "\t\tColumn Precision : " << jobCol.precision << endl;
|
||
oss3 << "\t\tColumn Scale : " << jobCol.scale << endl;
|
||
}
|
||
if( jobCol.typeName == ColDataTypeStr[CalpontSystemCatalog::UDECIMAL] ) {
|
||
oss3 << "\t\tColumn Precision : " << jobCol.precision << endl;
|
||
oss3 << "\t\tColumn Scale : " << jobCol.scale << endl;
|
||
}
|
||
|
||
if( jobCol.colType == 'D' ) {
|
||
oss3 << "\t\tDictionary Oid : " <<
|
||
jobCol.dctnry.dctnryOid << endl;
|
||
}
|
||
logger.logMsg( oss3.str(), MSGLVL_INFO2 );
|
||
} // end of loop through columns in a table
|
||
} // end of loop through tables
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Print brief contents of specified Job to specified logger object.
|
||
// logger - Log object to use in logging
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::printJobInfoBrief( Log& logger ) const
|
||
{
|
||
const Job& job = fJob;
|
||
|
||
ostringstream oss1;
|
||
oss1 << "XMLJobFile: Delim(" << job.fDelimiter << "); EnclosedBy(";
|
||
if (job.fEnclosedByChar)
|
||
oss1 << job.fEnclosedByChar;
|
||
else
|
||
oss1 << "n/a";
|
||
oss1 << "); EscapeChar(";
|
||
if (job.fEscapeChar)
|
||
oss1 << job.fEscapeChar;
|
||
else
|
||
oss1 << "n/a";
|
||
oss1 << "); ReadBufs(" << job.numberOfReadBuffers <<
|
||
"); ReadBufSize(" << job.readBufferSize <<
|
||
"); setvbufSize(" << job.writeBufferSize << ')';
|
||
logger.logMsg( oss1.str(), MSGLVL_INFO2 );
|
||
|
||
for( unsigned int i = 0; i < job.jobTableList.size(); i++ ) {
|
||
const JobTable& jobTable = job.jobTableList[i];
|
||
ostringstream oss2;
|
||
oss2 << " Table(" << jobTable.tblName <<
|
||
"); OID(" << jobTable.mapOid << ')' <<
|
||
"; MaxErrNum(" << jobTable.maxErrNum << ')';
|
||
logger.logMsg( oss2.str(), MSGLVL_INFO2 );
|
||
|
||
for( unsigned int j = 0; j < jobTable.fFldRefs.size(); j++ ) {
|
||
unsigned idx = jobTable.fFldRefs[j].fArrayIndex;
|
||
BulkFldColRel fldColType= jobTable.fFldRefs[j].fFldColType;
|
||
const JobColumn& jobCol = ((fldColType == BULK_FLDCOL_IGNORE_FIELD)?
|
||
jobTable.fIgnoredFields[idx] :
|
||
jobTable.colList[idx]);
|
||
ostringstream oss3;
|
||
if (fldColType == BULK_FLDCOL_COLUMN_DEFAULT)
|
||
oss3 << " DefaultColumn(" << jobCol.colName;
|
||
else
|
||
oss3 << " Column(" << jobCol.colName;
|
||
oss3 << "); OID(" << jobCol.mapOid <<
|
||
"); Type(" << jobCol.typeName <<
|
||
"); Width(" << jobCol.width <<
|
||
"); Comp(" << jobCol.compressionType;
|
||
if( jobCol.colType == 'D' )
|
||
oss3 << "); DctnryOid(" << jobCol.dctnry.dctnryOid;
|
||
oss3 << ')';
|
||
if (jobCol.autoIncFlag)
|
||
oss3 << "; autoInc";
|
||
if (jobCol.fNotNull)
|
||
oss3 << "; NotNull";
|
||
if (jobCol.fWithDefault)
|
||
oss3 << "; WithDefault";
|
||
logger.logMsg( oss3.str(), MSGLVL_INFO2 );
|
||
}
|
||
} // end of for( int i
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Process a node
|
||
// pNode - current node
|
||
// returns TRUE if success, FALSE otherwise
|
||
//------------------------------------------------------------------------------
|
||
bool XMLJob::processNode( xmlNode* pNode )
|
||
{
|
||
if( isTag( pNode, TAG_BULK_JOB ))
|
||
{
|
||
// no work for the BulkJob tag
|
||
}
|
||
else if( isTag( pNode, TAG_CREATE_DATE ))
|
||
setJobData( pNode, TAG_CREATE_DATE, true, TYPE_CHAR );
|
||
else if( isTag( pNode, TAG_CREATE_TIME ))
|
||
setJobData( pNode, TAG_CREATE_TIME, true, TYPE_CHAR );
|
||
else if( isTag( pNode, TAG_COLUMN ))
|
||
setJobData( pNode, TAG_COLUMN, false, TYPE_EMPTY );
|
||
else if( isTag( pNode, TAG_DEFAULT_COLUMN ))
|
||
setJobData( pNode, TAG_DEFAULT_COLUMN, false, TYPE_EMPTY );
|
||
else if( isTag( pNode, TAG_DESC ))
|
||
setJobData( pNode, TAG_DESC, true, TYPE_CHAR );
|
||
else if( isTag( pNode, TAG_ID ))
|
||
setJobData( pNode, TAG_ID, true, TYPE_INT );
|
||
else if( isTag( pNode, TAG_IGNORE_FIELD ))
|
||
setJobData( pNode, TAG_IGNORE_FIELD, false, TYPE_EMPTY );
|
||
else if( isTag( pNode, TAG_NAME ))
|
||
setJobData( pNode, TAG_NAME, true, TYPE_CHAR );
|
||
else if( isTag( pNode, TAG_PATH ))
|
||
setJobData( pNode, TAG_PATH, true, TYPE_CHAR );
|
||
else if( isTag( pNode, TAG_TABLE ))
|
||
setJobData( pNode, TAG_TABLE, false, TYPE_EMPTY );
|
||
else if( isTag( pNode, TAG_TYPE ))
|
||
setJobData( pNode, TAG_TYPE, true, TYPE_CHAR );
|
||
else if( isTag( pNode, TAG_USER ))
|
||
setJobData( pNode, TAG_USER, true, TYPE_CHAR );
|
||
else if( isTag( pNode, TAG_SCHEMA))
|
||
setJobData( pNode, TAG_SCHEMA, false, TYPE_EMPTY );
|
||
else if( isTag( pNode, TAG_READ_BUFFERS))
|
||
setJobData( pNode, TAG_READ_BUFFERS, false, TYPE_EMPTY );
|
||
else if( isTag( pNode, TAG_WRITE_BUFFER_SIZE))
|
||
setJobData( pNode, TAG_WRITE_BUFFER_SIZE, true, TYPE_INT);
|
||
else if( isTag( pNode, TAG_DELIMITER))
|
||
setJobData( pNode, TAG_DELIMITER, true, TYPE_CHAR);
|
||
else if( isTag( pNode, TAG_ENCLOSED_BY_CHAR))
|
||
setJobData( pNode, TAG_ENCLOSED_BY_CHAR, true, TYPE_CHAR);
|
||
else if( isTag( pNode, TAG_ESCAPE_CHAR))
|
||
setJobData( pNode, TAG_ESCAPE_CHAR, true, TYPE_CHAR);
|
||
else
|
||
{
|
||
ostringstream oss;
|
||
oss << "Unrecognized TAG in Job XML file: <" << pNode->name << ">";
|
||
throw runtime_error( oss.str() );
|
||
}
|
||
|
||
if (XMLOp::processNode( pNode ))
|
||
{
|
||
if( isTag( pNode, TAG_TABLE ))
|
||
{
|
||
postProcessTableNode();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Generic setter
|
||
// pNode - current node
|
||
// tag - xml tag
|
||
// bExpectContent - should node content be present to process
|
||
// tagType - data type
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::setJobData( xmlNode* pNode,
|
||
const xmlTag tag,
|
||
bool bExpectContent,
|
||
XML_DTYPE tagType )
|
||
{
|
||
int intVal = 0;
|
||
long long llVal = 0;
|
||
std::string bufString;
|
||
bool bSuccess = false;
|
||
|
||
if (bExpectContent)
|
||
{
|
||
if( tagType == TYPE_INT )
|
||
bSuccess = getNodeContent( pNode, &intVal, TYPE_INT );
|
||
else // longlong
|
||
if( tagType == TYPE_LONGLONG )
|
||
bSuccess = getNodeContent( pNode, &llVal, TYPE_LONGLONG );
|
||
else // char
|
||
if( tagType == TYPE_CHAR )
|
||
bSuccess = getNodeContentStr( pNode, bufString );
|
||
if (!bSuccess)
|
||
return;
|
||
}
|
||
|
||
// process tag content and attributes
|
||
switch( tag ) {
|
||
case TAG_READ_BUFFERS:
|
||
setReadBuffers( pNode );
|
||
break;
|
||
case TAG_COLUMN:
|
||
setJobDataColumn( pNode, false );
|
||
break;
|
||
case TAG_CREATE_DATE:
|
||
fJob.createDate = bufString;
|
||
break;
|
||
case TAG_CREATE_TIME:
|
||
fJob.createTime = bufString;
|
||
break;
|
||
case TAG_DEFAULT_COLUMN:
|
||
setJobDataColumn( pNode, true );
|
||
break;
|
||
case TAG_DESC:
|
||
fJob.desc = bufString;
|
||
break;
|
||
case TAG_ID:
|
||
fJob.id = intVal;
|
||
break;
|
||
case TAG_IGNORE_FIELD:
|
||
setJobDataIgnoreField( );
|
||
break;
|
||
case TAG_NAME:
|
||
fJob.name = bufString;
|
||
break;
|
||
case TAG_PATH:
|
||
// no action necessary, but keep for backwards compatability
|
||
break;
|
||
case TAG_TABLE:
|
||
setJobDataTable( pNode );
|
||
break;
|
||
case TAG_TYPE:
|
||
// no action necessary, but keep for backwards compatability
|
||
break;
|
||
case TAG_USER:
|
||
fJob.userName = bufString;
|
||
break;
|
||
case TAG_SCHEMA:
|
||
setSchema( pNode );
|
||
break;
|
||
case TAG_WRITE_BUFFER_SIZE:
|
||
fJob.writeBufferSize = intVal;
|
||
break;
|
||
case TAG_DELIMITER:
|
||
{
|
||
const char* buf = bufString.c_str();
|
||
if ((!strcmp(buf,"\\t")) ||
|
||
(!strcmp(buf,"'\\t'")))
|
||
{
|
||
fJob.fDelimiter = '\t';
|
||
}
|
||
else
|
||
{
|
||
fJob.fDelimiter = bufString[0];
|
||
}
|
||
break;
|
||
}
|
||
case TAG_ENCLOSED_BY_CHAR:
|
||
{
|
||
fJob.fEnclosedByChar = bufString[0];
|
||
break;
|
||
}
|
||
case TAG_ESCAPE_CHAR:
|
||
{
|
||
fJob.fEscapeChar = bufString[0];
|
||
break;
|
||
}
|
||
|
||
default: break;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Set table information parms.
|
||
// pNode - current node
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::setJobDataTable( xmlNode* pNode )
|
||
{
|
||
int intVal;
|
||
std::string bufString;
|
||
JobTable curTable;
|
||
|
||
if( getNodeAttributeStr( pNode, xmlTagTable[TAG_ORIG_NAME], bufString ) )
|
||
curTable.tblName = bufString;
|
||
if( getNodeAttributeStr( pNode, xmlTagTable[TAG_TBL_NAME], bufString ) )
|
||
curTable.tblName = bufString;
|
||
if (curTable.tblName.empty())
|
||
{
|
||
throw runtime_error(
|
||
"Required table name attribute (tblName) missing from Table tag");
|
||
}
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_TBL_OID], &intVal, TYPE_INT ) )
|
||
curTable.mapOid = intVal;
|
||
|
||
if( getNodeAttributeStr( pNode, xmlTagTable[TAG_LOAD_NAME], bufString ) )
|
||
curTable.loadFileName = bufString;
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_MAX_ERR_ROW], &intVal,
|
||
TYPE_INT))
|
||
curTable.maxErrNum = intVal;
|
||
|
||
fJob.jobTableList.push_back( curTable );
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Set column information parms.
|
||
// pNode - current node
|
||
// bDefaultCol - is this a <DefaultColumn> tag
|
||
//
|
||
// Note on Supported Tags: (Bug 2828)
|
||
// Note that the "notnull" and "defaultValue" attribute tags are not recognized
|
||
// by this function because by the time we added support for these tags, we had
|
||
// changed to only store the table and column names in the XML file. Much of
|
||
// the functionality in setJobDataColumn() is only present to provide backwards
|
||
// compatability for an old Job XML file that a user might still be using.
|
||
//
|
||
// Any other new tags probably don't need adding to setJobDataColumn() either,
|
||
// for the same reason.
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::setJobDataColumn( xmlNode* pNode, bool bDefaultCol )
|
||
{
|
||
int intVal;
|
||
std::string bufString;
|
||
JobColumn curColumn;
|
||
|
||
if( fJob.jobTableList.size() == 0 )
|
||
return;
|
||
|
||
int tableNo = fJob.jobTableList.size() - 1;
|
||
if( getNodeAttributeStr( pNode, xmlTagTable[TAG_ORIG_NAME], bufString ) )
|
||
curColumn.colName = bufString;
|
||
if( getNodeAttributeStr( pNode, xmlTagTable[TAG_COL_NAME], bufString ) )
|
||
curColumn.colName = bufString;
|
||
if (curColumn.colName.empty())
|
||
{
|
||
ostringstream oss;
|
||
oss << "Required column name attribute (colName) missing from "
|
||
"Column tag for table " <<
|
||
fJob.jobTableList[tableNo].tblName;
|
||
throw runtime_error( oss.str() );
|
||
}
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_COL_OID], &intVal, TYPE_INT ) )
|
||
curColumn.mapOid = intVal;
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_WIDTH], &intVal, TYPE_INT ) ) {
|
||
curColumn.width = intVal;
|
||
curColumn.definedWidth = intVal; //@Bug 3040
|
||
}
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_PRECISION], &intVal, TYPE_INT))
|
||
curColumn.precision = intVal;
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_SCALE], &intVal, TYPE_INT ) )
|
||
curColumn.scale = intVal;
|
||
|
||
if( getNodeAttributeStr( pNode, xmlTagTable[TAG_DATA_TYPE], bufString ) )
|
||
curColumn.typeName = bufString;
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_COMPRESS_TYPE], &intVal,
|
||
TYPE_INT))
|
||
{
|
||
curColumn.compressionType = intVal;
|
||
curColumn.dctnry.fCompressionType = intVal;
|
||
}
|
||
|
||
if( getNodeAttribute( pNode, xmlTagTable[TAG_AUTOINCREMENT_FLAG],
|
||
&intVal, TYPE_INT))
|
||
{
|
||
if (intVal)
|
||
curColumn.autoIncFlag = true;
|
||
else
|
||
curColumn.autoIncFlag = false;
|
||
}
|
||
|
||
if( getNodeAttributeStr( pNode, xmlTagTable[TAG_COL_TYPE], bufString ) ) {
|
||
const char* buf = bufString.c_str();
|
||
if( !strcmp( buf, "D" ) ) {
|
||
curColumn.colType = 'D';
|
||
|
||
// @Bug 2565: Retain dictionary width to use in truncating strings,
|
||
// since BulkLoad eventually stores column token width in 'width'.
|
||
curColumn.dctnryWidth = curColumn.width;
|
||
|
||
if( getNodeAttribute( pNode,
|
||
xmlTagTable[TAG_DVAL_OID],
|
||
&intVal,
|
||
TYPE_INT ) )
|
||
curColumn.dctnry.dctnryOid = intVal;
|
||
}
|
||
}
|
||
|
||
// This is a workaround that DBBuilder can not pass decimal type to XML file
|
||
if( ( curColumn.typeName == ColDataTypeStr[CalpontSystemCatalog::INT] ||
|
||
curColumn.typeName == ColDataTypeStr[CalpontSystemCatalog::BIGINT] ||
|
||
curColumn.typeName == ColDataTypeStr[CalpontSystemCatalog::SMALLINT]||
|
||
curColumn.typeName == ColDataTypeStr[CalpontSystemCatalog::TINYINT])&&
|
||
curColumn.scale > 0 )
|
||
curColumn.typeName = ColDataTypeStr[CalpontSystemCatalog::DECIMAL];
|
||
// end of workaround
|
||
|
||
// Initialize the saturation limits for this column
|
||
initSatLimits( curColumn );
|
||
|
||
// Save default columns in separate list, so that we can intentionally
|
||
// add/keep them at the "end" of colList later, after all other columns.
|
||
if (bDefaultCol) // temporarily save in separate list
|
||
{
|
||
curColumn.fFldColRelation = BULK_FLDCOL_COLUMN_DEFAULT;
|
||
fDefaultColumns.push_back ( curColumn );
|
||
}
|
||
else
|
||
{
|
||
// Add to list of db columns to be loaded
|
||
curColumn.fFldColRelation = BULK_FLDCOL_COLUMN_FIELD;
|
||
fJob.jobTableList[tableNo].colList.push_back ( curColumn );
|
||
|
||
// Add to combined field list of columns and ignored fields
|
||
JobFieldRef fieldRef( BULK_FLDCOL_COLUMN_FIELD,
|
||
fJob.jobTableList[tableNo].colList.size()-1 );
|
||
fJob.jobTableList[tableNo].fFldRefs.push_back( fieldRef );
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Set column information parms for an input field that is to be ignored
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::setJobDataIgnoreField( )
|
||
{
|
||
JobColumn curColumn;
|
||
|
||
int tableNo = fJob.jobTableList.size() - 1;
|
||
ostringstream oss;
|
||
oss << "IgnoreField" << fJob.jobTableList[tableNo].fFldRefs.size()+1;
|
||
curColumn.colName = oss.str();
|
||
|
||
// Add to list of ignored fields
|
||
curColumn.fFldColRelation = BULK_FLDCOL_IGNORE_FIELD;
|
||
fJob.jobTableList[tableNo].fIgnoredFields.push_back( curColumn );
|
||
|
||
// Add to combined field list of columns and ignored fields
|
||
JobFieldRef fieldRef( BULK_FLDCOL_IGNORE_FIELD,
|
||
fJob.jobTableList[tableNo].fIgnoredFields.size()-1 );
|
||
fJob.jobTableList[tableNo].fFldRefs.push_back ( fieldRef );
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Initialize the saturation limits for the specified column.
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::initSatLimits( JobColumn& curColumn ) const
|
||
{
|
||
// If one of the integer types, we set the min/max saturation value.
|
||
// For DECIMAL columns this will vary with the precision.
|
||
if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::INT] ) {
|
||
curColumn.fMinIntSat = MIN_INT;
|
||
curColumn.fMaxIntSat = MAX_INT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::UINT] ) {
|
||
curColumn.fMinIntSat = MIN_UINT;
|
||
curColumn.fMaxIntSat = MAX_UINT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::BIGINT] ) {
|
||
curColumn.fMinIntSat = MIN_BIGINT;
|
||
curColumn.fMaxIntSat = MAX_BIGINT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::UBIGINT] ) {
|
||
curColumn.fMinIntSat = MIN_UBIGINT;
|
||
curColumn.fMaxIntSat = MAX_UBIGINT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::SMALLINT] ) {
|
||
curColumn.fMinIntSat = MIN_SMALLINT;
|
||
curColumn.fMaxIntSat = MAX_SMALLINT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::USMALLINT] ) {
|
||
curColumn.fMinIntSat = MIN_USMALLINT;
|
||
curColumn.fMaxIntSat = MAX_USMALLINT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::TINYINT] ) {
|
||
curColumn.fMinIntSat = MIN_TINYINT;
|
||
curColumn.fMaxIntSat = MAX_TINYINT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::UTINYINT] ) {
|
||
curColumn.fMinIntSat = MIN_UTINYINT;
|
||
curColumn.fMaxIntSat = MAX_UTINYINT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::DECIMAL] ) {
|
||
curColumn.fMinIntSat = -infinidb_precision[curColumn.precision];
|
||
curColumn.fMaxIntSat = infinidb_precision[curColumn.precision];
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::UDECIMAL] ) {
|
||
curColumn.fMinIntSat = 0;
|
||
curColumn.fMaxIntSat = infinidb_precision[curColumn.precision];
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::FLOAT] ) {
|
||
curColumn.fMinDblSat = MIN_FLOAT;
|
||
curColumn.fMaxDblSat = MAX_FLOAT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::UFLOAT] ) {
|
||
curColumn.fMinDblSat = 0.0;
|
||
curColumn.fMaxDblSat = MAX_FLOAT;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::DOUBLE] ) {
|
||
curColumn.fMinDblSat = MIN_DOUBLE;
|
||
curColumn.fMaxDblSat = MAX_DOUBLE;
|
||
}
|
||
else if ( curColumn.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::UDOUBLE] ) {
|
||
curColumn.fMinDblSat = 0.0;
|
||
curColumn.fMaxDblSat = MAX_DOUBLE;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Set Read Buffers attributes
|
||
// pNode - current node
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::setReadBuffers( xmlNode* pNode )
|
||
{
|
||
int intVal = 0;
|
||
|
||
if(getNodeAttribute(pNode,
|
||
xmlTagTable[TAG_NO_OF_READ_BUFFERS],
|
||
&intVal,
|
||
TYPE_INT ))
|
||
fJob.numberOfReadBuffers = intVal;
|
||
|
||
if(getNodeAttribute(pNode,
|
||
xmlTagTable[TAG_READ_BUFFER_SIZE],
|
||
&intVal,
|
||
TYPE_INT ))
|
||
fJob.readBufferSize = intVal;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Set Schema attributes
|
||
// pNode - current node
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::setSchema( xmlNode* pNode )
|
||
{
|
||
std::string bufString;
|
||
|
||
if( getNodeAttributeStr( pNode,
|
||
xmlTagTable[TAG_SCHEMA_NAME],
|
||
bufString ) )
|
||
fJob.schema = bufString;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Transfer any/all <DefaultColumn> columns from temporary fDefaultColumns, to
|
||
// the end of the column/field lists.
|
||
// It is assumed that we are working with the last table in jobTableList.
|
||
// Then get additional information from system catalog to finish populating
|
||
// our Job structs with all the table and column attributes we need.
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::postProcessTableNode()
|
||
{
|
||
bool bValidateNoDefColWithoutDefValue = false;
|
||
if (fDefaultColumns.size() > 0)
|
||
{
|
||
bValidateNoDefColWithoutDefValue = true;
|
||
int tableNo = fJob.jobTableList.size() - 1;
|
||
|
||
for (unsigned k=0; k<fDefaultColumns.size(); k++)
|
||
{
|
||
// Add to list of db columns to be loaded
|
||
fJob.jobTableList[tableNo].colList.push_back( fDefaultColumns[k] );
|
||
|
||
// Add to combined list of columns and ignored fields
|
||
JobFieldRef fieldRef( BULK_FLDCOL_COLUMN_DEFAULT,
|
||
fJob.jobTableList[tableNo].colList.size()-1 );
|
||
fJob.jobTableList[tableNo].fFldRefs.push_back( fieldRef );
|
||
}
|
||
fDefaultColumns.clear();
|
||
}
|
||
|
||
// Supplement xml file contents with information from syscat
|
||
execplan::CalpontSystemCatalog::RIDList colRidList;
|
||
fillInXMLDataAsLoaded( colRidList );
|
||
|
||
// After getting all the system catalog information...
|
||
// Validate that if there are any <DefaultColumn> tags for a NotNull
|
||
// column, that the column is defined as NotNull With Default.
|
||
if (bValidateNoDefColWithoutDefValue)
|
||
{
|
||
int tableNo = fJob.jobTableList.size() - 1;
|
||
|
||
for (unsigned int iCol=0;
|
||
iCol<fJob.jobTableList[tableNo].colList.size(); iCol++)
|
||
{
|
||
JobColumn& col = fJob.jobTableList[tableNo].colList[iCol];
|
||
|
||
if (col.fFldColRelation == BULK_FLDCOL_COLUMN_DEFAULT)
|
||
{
|
||
if ( (col.fNotNull) && (!col.fWithDefault) )
|
||
{
|
||
std::ostringstream oss;
|
||
oss << "Column " << col.colName << " in table " <<
|
||
fJob.jobTableList[tableNo].tblName << " is NotNull "
|
||
"w/o default; cannot be used with <DefaultColumn>";
|
||
throw std::runtime_error( oss.str() );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Make sure all Columns in the DB are counted for with <Column> or
|
||
// <DefaultColumn> tags (unless validate is disabled)
|
||
if (fValidateColList)
|
||
validateAllColumnsHaveTags( colRidList );
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Use the table and column names from the last <Table> just loaded, to
|
||
// collect the remaining information from the system catalog, in order to
|
||
// populate the JobColumn structure.
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::fillInXMLDataAsLoaded(
|
||
execplan::CalpontSystemCatalog::RIDList& colRidList)
|
||
{
|
||
boost::shared_ptr<execplan::CalpontSystemCatalog> cat =
|
||
execplan::CalpontSystemCatalog::makeCalpontSystemCatalog(
|
||
BULK_SYSCAT_SESSION_ID);
|
||
cat->identity(execplan::CalpontSystemCatalog::EC);
|
||
|
||
// Get the table and column attributes for the last <Table> processed
|
||
unsigned int iTbl = fJob.jobTableList.size()-1;
|
||
JobTable& tbl = fJob.jobTableList[iTbl];
|
||
|
||
std::string tblName;
|
||
string::size_type startName = tbl.tblName.rfind('.');
|
||
if (startName == string::npos)
|
||
tblName.assign( tbl.tblName );
|
||
else
|
||
tblName.assign( tbl.tblName.substr(startName+1) );
|
||
|
||
execplan::CalpontSystemCatalog::TableName table(
|
||
fJob.schema, tblName );
|
||
if (fJob.jobTableList[iTbl].mapOid == 0)
|
||
{
|
||
execplan::CalpontSystemCatalog::OID tblOid =
|
||
cat->tableRID(table).objnum;
|
||
tbl.mapOid = tblOid;
|
||
}
|
||
|
||
// This call is made to improve performance.
|
||
// The call forces all the column information for this table to be
|
||
// cached at one time, instead of doing it piece-meal through repeated
|
||
// calls to lookupOID().
|
||
colRidList = cat->columnRIDs(table, true);
|
||
|
||
// Loop through the columns to get the column attributes
|
||
for (unsigned int iCol=0;
|
||
iCol<fJob.jobTableList[iTbl].colList.size(); iCol++)
|
||
{
|
||
JobColumn& col = fJob.jobTableList[iTbl].colList[iCol];
|
||
|
||
if (col.mapOid == 0)
|
||
{
|
||
execplan::CalpontSystemCatalog::TableColName column;
|
||
column.schema = fJob.schema;
|
||
column.table = tblName;
|
||
column.column = col.colName;
|
||
execplan::CalpontSystemCatalog::OID colOid =
|
||
cat->lookupOID( column );
|
||
if (colOid < 0)
|
||
{
|
||
ostringstream oss;
|
||
oss << "Column OID lookup failed for: " << column;
|
||
throw runtime_error( oss.str() );
|
||
}
|
||
col.mapOid = colOid;
|
||
|
||
execplan::CalpontSystemCatalog::ColType colType =
|
||
cat->colType( col.mapOid );
|
||
|
||
col.width = colType.colWidth;
|
||
col.definedWidth = colType.colWidth;
|
||
if ((colType.scale > 0) ||
|
||
(colType.colDataType ==
|
||
execplan::CalpontSystemCatalog::DECIMAL) ||
|
||
(colType.colDataType ==
|
||
execplan::CalpontSystemCatalog::UDECIMAL))
|
||
{
|
||
col.precision = colType.precision;
|
||
col.scale = colType.scale;
|
||
}
|
||
col.typeName = ColDataTypeStr[colType.colDataType];
|
||
col.compressionType = colType.compressionType;
|
||
col.dctnry.fCompressionType = colType.compressionType;
|
||
if (colType.autoincrement)
|
||
col.autoIncFlag = true;
|
||
else
|
||
col.autoIncFlag = false;
|
||
// Initialize NotNull and Default Value (based on data type)
|
||
fillInXMLDataNotNullDefault( tbl.tblName, colType, col );
|
||
|
||
if (colType.ddn.dictOID > 0)
|
||
{
|
||
col.colType = 'D';
|
||
col.dctnryWidth = colType.colWidth;
|
||
col.dctnry.dctnryOid = colType.ddn.dictOID;
|
||
}
|
||
|
||
// @bug3801: For backwards compatability, we treat
|
||
// integer types with nonzero 0 scale as decimal if scale > 0
|
||
if( ((col.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::INT]) ||
|
||
(col.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::BIGINT]) ||
|
||
(col.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::SMALLINT]) ||
|
||
(col.typeName ==
|
||
ColDataTypeStr[CalpontSystemCatalog::TINYINT])) &&
|
||
(col.scale > 0) )
|
||
{
|
||
col.typeName = ColDataTypeStr[CalpontSystemCatalog::DECIMAL];
|
||
}
|
||
|
||
// Initialize the saturation limits for this column
|
||
initSatLimits( col );
|
||
}
|
||
} // end of loop through columns
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Using information from the system catalog (in colType), fill in the
|
||
// applicable NotNull Default values into the specified JobColumn.
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::fillInXMLDataNotNullDefault(
|
||
const std::string& fullTblName,
|
||
execplan::CalpontSystemCatalog::ColType& colType,
|
||
JobColumn& col )
|
||
{
|
||
const std::string col_defaultValue(colType.defaultValue);
|
||
|
||
if (colType.constraintType ==
|
||
execplan::CalpontSystemCatalog::NOTNULL_CONSTRAINT)
|
||
{
|
||
col.fNotNull = true;
|
||
if (!col_defaultValue.empty())
|
||
col.fWithDefault = true;
|
||
}
|
||
else if (colType.constraintType ==
|
||
execplan::CalpontSystemCatalog::DEFAULT_CONSTRAINT)
|
||
{
|
||
col.fWithDefault = true;
|
||
}
|
||
|
||
if (col.fWithDefault)
|
||
{
|
||
bool bDefaultConvertError = false;
|
||
|
||
// Convert Default Value.
|
||
// We go ahead and report basic format conversion error;
|
||
// but we don't do complete validation (like checking to see
|
||
// if the default is too large for the given integer type),
|
||
// because we assume DDL is fully validating the default value.
|
||
switch (colType.colDataType)
|
||
{
|
||
case execplan::CalpontSystemCatalog::BIT:
|
||
case execplan::CalpontSystemCatalog::TINYINT:
|
||
case execplan::CalpontSystemCatalog::SMALLINT:
|
||
case execplan::CalpontSystemCatalog::MEDINT:
|
||
case execplan::CalpontSystemCatalog::INT:
|
||
case execplan::CalpontSystemCatalog::BIGINT:
|
||
{
|
||
errno = 0;
|
||
col.fDefaultInt = strtoll(col_defaultValue.c_str(),0,10);
|
||
if (errno == ERANGE)
|
||
bDefaultConvertError = true;
|
||
break;
|
||
}
|
||
|
||
case execplan::CalpontSystemCatalog::UTINYINT:
|
||
case execplan::CalpontSystemCatalog::USMALLINT:
|
||
case execplan::CalpontSystemCatalog::UMEDINT:
|
||
case execplan::CalpontSystemCatalog::UINT:
|
||
case execplan::CalpontSystemCatalog::UBIGINT:
|
||
{
|
||
errno = 0;
|
||
col.fDefaultUInt = strtoull(col_defaultValue.c_str(),0,10);
|
||
if (errno == ERANGE)
|
||
bDefaultConvertError = true;
|
||
break;
|
||
}
|
||
|
||
case execplan::CalpontSystemCatalog::DECIMAL:
|
||
case execplan::CalpontSystemCatalog::UDECIMAL:
|
||
{
|
||
col.fDefaultInt = Convertor::convertDecimalString(
|
||
col_defaultValue.c_str(),
|
||
col_defaultValue.length(),
|
||
colType.scale);
|
||
if (errno == ERANGE)
|
||
bDefaultConvertError = true;
|
||
break;
|
||
}
|
||
|
||
case execplan::CalpontSystemCatalog::DATE:
|
||
{
|
||
int convertStatus;
|
||
int32_t dt =
|
||
dataconvert::DataConvert::convertColumnDate(
|
||
col_defaultValue.c_str(),
|
||
dataconvert::CALPONTDATE_ENUM, convertStatus,
|
||
col_defaultValue.length() );
|
||
if (convertStatus != 0)
|
||
bDefaultConvertError = true;
|
||
col.fDefaultInt = dt;
|
||
break;
|
||
}
|
||
|
||
case execplan::CalpontSystemCatalog::DATETIME:
|
||
{
|
||
int convertStatus;
|
||
int64_t dt =
|
||
dataconvert::DataConvert::convertColumnDatetime(
|
||
col_defaultValue.c_str(),
|
||
dataconvert::CALPONTDATETIME_ENUM, convertStatus,
|
||
col_defaultValue.length() );
|
||
if (convertStatus != 0)
|
||
bDefaultConvertError = true;
|
||
col.fDefaultInt = dt;
|
||
break;
|
||
}
|
||
|
||
case execplan::CalpontSystemCatalog::FLOAT:
|
||
case execplan::CalpontSystemCatalog::DOUBLE:
|
||
case execplan::CalpontSystemCatalog::UFLOAT:
|
||
case execplan::CalpontSystemCatalog::UDOUBLE:
|
||
{
|
||
errno = 0;
|
||
col.fDefaultDbl = strtod(col_defaultValue.c_str(),0);
|
||
if (errno == ERANGE)
|
||
bDefaultConvertError = true;
|
||
break;
|
||
}
|
||
|
||
default:
|
||
{
|
||
col.fDefaultChr = col_defaultValue;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (bDefaultConvertError)
|
||
{
|
||
std::ostringstream oss;
|
||
oss << "Column " << col.colName << " in table " << fullTblName <<
|
||
" has an invalid default value in system catalog.";
|
||
throw std::runtime_error( oss.str() );
|
||
}
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Use the table and column names from the last <Table> just loaded, to
|
||
// validate that all the columns have a <Column> or <DefaultColumn> tag
|
||
// present in the job XML file.
|
||
//------------------------------------------------------------------------------
|
||
void XMLJob::validateAllColumnsHaveTags(
|
||
const execplan::CalpontSystemCatalog::RIDList& colRidList) const
|
||
{
|
||
// Validate column list for the last <Table> processed
|
||
unsigned int iTbl = fJob.jobTableList.size()-1;
|
||
const JobTable& tbl = fJob.jobTableList[iTbl];
|
||
|
||
std::string tblName;
|
||
string::size_type startName = tbl.tblName.rfind('.');
|
||
if (startName == string::npos)
|
||
tblName.assign( tbl.tblName );
|
||
else
|
||
tblName.assign( tbl.tblName.substr(startName+1) );
|
||
|
||
try
|
||
{
|
||
// Loop through column tags, saving col OIDs to a std::set for lookups
|
||
std::set<execplan::CalpontSystemCatalog::OID> colOIDList;
|
||
typedef std::set<execplan::CalpontSystemCatalog::OID>::iterator SetIter;
|
||
std::pair<SetIter,bool> retVal;
|
||
for (unsigned int iCol=0;
|
||
iCol<fJob.jobTableList[iTbl].colList.size(); iCol++)
|
||
{
|
||
const JobColumn& col = fJob.jobTableList[iTbl].colList[iCol];
|
||
retVal = colOIDList.insert( col.mapOid );
|
||
if (!retVal.second)
|
||
{
|
||
boost::shared_ptr<execplan::CalpontSystemCatalog> cat =
|
||
execplan::CalpontSystemCatalog::makeCalpontSystemCatalog(
|
||
BULK_SYSCAT_SESSION_ID);
|
||
cat->identity(execplan::CalpontSystemCatalog::EC);
|
||
|
||
execplan::CalpontSystemCatalog::TableColName dbColName =
|
||
cat->colName( col.mapOid );
|
||
std::ostringstream oss;
|
||
oss << "Column " << dbColName.column << " referenced in Job XML"
|
||
" file more than once.";
|
||
throw std::runtime_error( oss.str() );
|
||
}
|
||
}
|
||
|
||
SetIter pos;
|
||
|
||
// Loop thru cols in system catalog and verify that each one has a tag
|
||
execplan::CalpontSystemCatalog::RIDList::const_iterator rid_iterator =
|
||
colRidList.begin();
|
||
while (rid_iterator != colRidList.end())
|
||
{
|
||
pos = colOIDList.find( rid_iterator->objnum );
|
||
if (pos != colOIDList.end())
|
||
{
|
||
colOIDList.erase( pos ); // through with this column, so delete
|
||
}
|
||
else
|
||
{
|
||
boost::shared_ptr<execplan::CalpontSystemCatalog> cat =
|
||
execplan::CalpontSystemCatalog::makeCalpontSystemCatalog(
|
||
BULK_SYSCAT_SESSION_ID);
|
||
cat->identity(execplan::CalpontSystemCatalog::EC);
|
||
|
||
execplan::CalpontSystemCatalog::TableColName dbColName =
|
||
cat->colName( rid_iterator->objnum );
|
||
std::ostringstream oss;
|
||
oss << "No tag present in Job XML file for DB column: " <<
|
||
dbColName.column;
|
||
throw std::runtime_error( oss.str() );
|
||
}
|
||
|
||
++rid_iterator;
|
||
}
|
||
}
|
||
catch (std::exception& ex)
|
||
{
|
||
std::ostringstream oss;
|
||
oss << "Error validating column list for table " <<
|
||
fJob.schema << '.' << tblName << "; " << ex.what();
|
||
throw std::runtime_error( oss.str() );
|
||
}
|
||
catch (...)
|
||
{
|
||
std::ostringstream oss;
|
||
oss << "Unknown Error validating column list for table " <<
|
||
fJob.schema << '.' << tblName;
|
||
throw std::runtime_error( oss.str() );
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Generate a permanent or temporary Job XML file name path.
|
||
// sXMLJobDir Command line override for complete Job directory path
|
||
// jobDIr Job subdirectory under default <BulkRoot> path
|
||
// jobId Job ID
|
||
// bTempFile Are we creating a temporary Job Xml File
|
||
// schmaName If temp file, this is schema name to use
|
||
// tableName If temp file, this is the table name to use
|
||
// xmlDirPath The complete Job XML file path that is constructed
|
||
// errMsg Relevant error message if return value is not NO_ERROR.
|
||
//------------------------------------------------------------------------------
|
||
/* static */
|
||
int XMLJob::genJobXMLFileName(
|
||
const string& sXMLJobDir,
|
||
const string& jobDir,
|
||
const string& jobId,
|
||
bool bTempFile,
|
||
const string& schemaName,
|
||
const string& tableName,
|
||
boost::filesystem::path& xmlFilePath,
|
||
string& errMsg,
|
||
std::string& tableOIDStr )
|
||
{
|
||
// get full file directory path for XML job description file
|
||
if (sXMLJobDir.empty())
|
||
{
|
||
xmlFilePath = Config::getBulkRoot();
|
||
xmlFilePath /= jobDir;
|
||
}
|
||
else
|
||
{
|
||
xmlFilePath = sXMLJobDir;
|
||
|
||
//If filespec doesn't begin with a '/' (i.e. it's not an absolute path),
|
||
// attempt to make it absolute so that we can log the full pathname.
|
||
if (!xmlFilePath.has_root_path())
|
||
{
|
||
#ifdef _MSC_VER
|
||
// nothing else to do
|
||
#else
|
||
char cwdPath[4096];
|
||
getcwd(cwdPath, sizeof(cwdPath));
|
||
string trailingPath(xmlFilePath.string());
|
||
xmlFilePath = cwdPath;
|
||
xmlFilePath /= trailingPath;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
// Append the file name to the directory path
|
||
string jobFileName;
|
||
if (bTempFile)
|
||
{
|
||
// Create tmp directory if does not exist
|
||
RETURN_ON_ERROR( createTempJobDir( xmlFilePath.string(), errMsg ) );
|
||
jobFileName +=tableOIDStr;
|
||
//jobFileName += schemaName;
|
||
// jobFileName += '_';
|
||
// jobFileName += tableName;
|
||
jobFileName += "_D";
|
||
|
||
string now(boost::posix_time::to_iso_string( boost::posix_time::second_clock::local_time()));
|
||
|
||
// microseconds
|
||
struct timeval tp;
|
||
gettimeofday(&tp, 0);
|
||
ostringstream usec;
|
||
usec << setfill('0') << setw(6) << tp.tv_usec;
|
||
|
||
jobFileName += now.substr(0, 8);
|
||
jobFileName += "_T";
|
||
jobFileName += now.substr(9, 6);
|
||
jobFileName += "_S";
|
||
jobFileName += usec.str();
|
||
jobFileName += '_';
|
||
}
|
||
|
||
jobFileName += "Job_";
|
||
jobFileName += jobId;
|
||
jobFileName += ".xml";
|
||
|
||
xmlFilePath /= jobFileName;
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Create directory for temporary XML job description files.
|
||
// OAM restart should delete any/all files in this directory.
|
||
//------------------------------------------------------------------------------
|
||
/* static */
|
||
int XMLJob::createTempJobDir( const string& xmlFilePath,
|
||
string& errMsg )
|
||
{
|
||
boost::filesystem::path pathDir(xmlFilePath);
|
||
|
||
// create temp directory for XML job file if it does not exist
|
||
try
|
||
{
|
||
if ( !boost::filesystem::exists( xmlFilePath ) )
|
||
{
|
||
string boostErrString;
|
||
try
|
||
{
|
||
boost::filesystem::create_directories(pathDir);
|
||
}
|
||
catch (exception& ex)
|
||
{
|
||
// ignore exception for now; we may have just had a
|
||
// race condition where 2 jobs were creating dirs.
|
||
boostErrString = ex.what();
|
||
}
|
||
|
||
if ( !boost::filesystem::exists( xmlFilePath ) )
|
||
{
|
||
ostringstream oss;
|
||
oss << "Error creating XML temp job file directory(1) " <<
|
||
xmlFilePath << "; " << boostErrString;
|
||
errMsg = oss.str();
|
||
|
||
return ERR_DIR_CREATE;
|
||
}
|
||
}
|
||
}
|
||
catch (exception& ex)
|
||
{
|
||
ostringstream oss;
|
||
oss << "Error creating XML temp job file directory(2) " <<
|
||
xmlFilePath << "; " << ex.what();
|
||
errMsg = oss.str();
|
||
|
||
return ERR_DIR_CREATE;
|
||
}
|
||
|
||
if (!boost::filesystem::is_directory(pathDir) )
|
||
{
|
||
ostringstream oss;
|
||
oss << "Error creating XML temp job file directory " <<
|
||
xmlFilePath << "; path already exists as non-directory" << endl;
|
||
errMsg = oss.str();
|
||
|
||
return ERR_DIR_CREATE;
|
||
}
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
} //end of namespace
|
||
|