/*
FILE:     CifSchemaMap.C
*/
/*
VERSION:  2.201
*/
/*
DATE:     8/30/2004
*/
/*
  Comments and Questions to: sw-help@rcsb.rutgers.edu
*/
/*
COPYRIGHT 1999-2004 Rutgers - The State University of New Jersey

This software is provided WITHOUT WARRANTY OF MERCHANTABILITY OR
FITNESS FOR A PARTICULAR PURPOSE OR ANY OTHER WARRANTY, EXPRESS OR
IMPLIED.  RUTGERS MAKE NO REPRESENTATION OR WARRANTY THAT THE
SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT OR OTHER
PROPRIETARY RIGHT.

The user of this software shall indemnify, hold harmless and defend
Rutgers, its governors, trustees, officers, employees, students,
agents and the authors against any and all claims, suits,
losses, liabilities, damages, costs, fees, and expenses including
reasonable attorneys' fees resulting from or arising out of the
use of this software.  This indemnification shall include, but is
not limited to, any and all claims alleging products liability.
*/
/*
               PDB SOFTWARE LICENSE AGREEMENT

BY CLICKING THE ACCEPTANCE BUTTON OR INSTALLING OR USING 
THIS "SOFTWARE, THE INDIVIDUAL OR ENTITY LICENSING THE  
SOFTWARE ("LICENSEE") IS CONSENTING TO BE BOUND BY AND IS 
BECOMING A PARTY TO THIS AGREEMENT.  IF LICENSEE DOES NOT 
AGREE TO ALL OF THE TERMS OF THIS AGREEMENT
THE LICENSEE MUST NOT INSTALL OR USE THE SOFTWARE.

1. LICENSE AGREEMENT

This is a license between you ("Licensee") and the Protein Data Bank (PDB) 
at Rutgers, The State University of New Jersey (hereafter referred to 
as "RUTGERS").   The software is owned by RUTGERS and protected by 
copyright laws, and some elements are protected by laws governing 
trademarks, trade dress and trade secrets, and may be protected by 
patent laws. 

2. LICENSE GRANT

RUTGERS grants you, and you hereby accept, non-exclusive, royalty-free 
perpetual license to install, use, modify, prepare derivative works, 
incorporate into other computer software, and distribute in binary 
and source code format, or any derivative work thereof, together with 
any associated media, printed materials, and on-line or electronic 
documentation (if any) provided by RUTGERS (collectively, the "SOFTWARE"), 
subject to the following terms and conditions: (i) any distribution 
of the SOFTWARE shall bind the receiver to the terms and conditions 
of this Agreement; (ii) any distribution of the SOFTWARE in modified 
form shall clearly state that the SOFTWARE has been modified from 
the version originally obtained from RUTGERS.  

2. COPYRIGHT; RETENTION OF RIGHTS.  

The above license grant is conditioned on the following: (i) you must 
reproduce all copyright notices and other proprietary notices on any 
copies of the SOFTWARE and you must not remove such notices; (ii) in 
the event you compile the SOFTWARE, you will include the copyright 
notice with the binary in such a manner as to allow it to be easily 
viewable; (iii) if you incorporate the SOFTWARE into other code, you 
must provide notice that the code contains the SOFTWARE and include 
a copy of the copyright notices and other proprietary notices.  All 
copies of the SOFTWARE shall be subject to the terms of this Agreement.  

3. NO MAINTENANCE OR SUPPORT; TREATMENT OF ENHANCEMENTS 

RUTGERS is under no obligation whatsoever to: (i) provide maintenance 
or support for the SOFTWARE; or (ii) to notify you of bug fixes, patches, 
or upgrades to the features, functionality or performance of the 
SOFTWARE ("Enhancements") (if any), whether developed by RUTGERS 
or third parties.  If, in its sole discretion, RUTGERS makes an 
Enhancement available to you and RUTGERS does not separately enter 
into a written license agreement with you relating to such bug fix, 
patch or upgrade, then it shall be deemed incorporated into the SOFTWARE 
and subject to this Agreement. You are under no obligation whatsoever 
to provide any Enhancements to RUTGERS or the public that you may 
develop over time; however, if you choose to provide your Enhancements 
to RUTGERS, or if you choose to otherwise publish or distribute your 
Enhancements, in source code form without contemporaneously requiring 
end users or RUTGERS to enter into a separate written license agreement 
for such Enhancements, then you hereby grant RUTGERS a non-exclusive,
royalty-free perpetual license to install, use, modify, prepare
derivative works, incorporate into the SOFTWARE or other computer
software, distribute, and sublicense your Enhancements or derivative
works thereof, in binary and source code form.

4. FEES.  There is no license fee for the SOFTWARE.  If Licensee
wishes to receive the SOFTWARE on media, there may be a small charge
for the media and for shipping and handling.  Licensee is
responsible for any and all taxes.

5. TERMINATION.  Without prejudice to any other rights, Licensor
may terminate this Agreement if Licensee breaches any of its terms
and conditions.  Upon termination, Licensee shall destroy all
copies of the SOFTWARE.

6. PROPRIETARY RIGHTS.  Title, ownership rights, and intellectual
property rights in the Product shall remain with RUTGERS.  Licensee 
acknowledges such ownership and intellectual property rights and will 
not take any action to jeopardize, limit or interfere in any manner 
with RUTGERS' ownership of or rights with respect to the SOFTWARE.  
The SOFTWARE is protected by copyright and other intellectual 
property laws and by international treaties.  Title and related 
rights in the content accessed through the SOFTWARE is the property 
of the applicable content owner and is protected by applicable law.  
The license granted under this Agreement gives Licensee no rights to such
content.

7. DISCLAIMER OF WARRANTY.  THE SOFTWARE IS PROVIDED FREE OF 
CHARGE, AND, THEREFORE, ON AN "AS IS" BASIS, WITHOUT WARRANTY OF 
ANY KIND, INCLUDING WITHOUT LIMITATION THE WARRANTIES THAT IT 
IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE 
OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND 
PERFORMANCE OF THE SOFTWARE IS BORNE BY LICENSEE.  SHOULD THE 
SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, THE LICENSEE AND NOT 
LICENSOR ASSUMES THE ENTIRE COST OF ANY SERVICE AND REPAIR.  
THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF 
THIS AGREEMENT.  NO USE OF THE PRODUCT IS AUTHORIZED HEREUNDER 
EXCEPT UNDER THIS DISCLAIMER.

8. LIMITATION OF LIABILITY.  TO THE MAXIMUM EXTENT PERMITTED BY
APPLICABLE LAW,  IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY 
INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 
OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, INCLUDING, 
WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK 
STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL 
OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF ADVISED OF THE
POSSIBILITY THEREOF. 
*/
 
#include "CifSchemaMap.h"

#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

static char _SQL_FILE[]            = "CIFLOADER.isql";
static char _IND_FILE[]            = "CIFLOADER_UPDATE_INDICES.sql";

static char _SCHEMA_SQL_FILE[]     = "CIFLOADER_SCHEMA.sql";
static char _SCHEMA_XML_FILE[]     = "CIFLOADER_SCHEMA_XML.xsd";
static char _COMMAND_FILE[]        = "CIFLOADER_COMMANDS.csh";
static char _SCHEMA_COMMAND_FILE[] = "CIFLOADER_SCHEMA_COMMANDS.csh";
static char _LOG_FILE[]            = "SchemaMap.log";
static char _INPUT_FILE[512];
static char _NS_DEFAULT[80];
static char _HASH_ID[40];

static char *escapeString(const char *inStr);
static void _ConvertDataTypeXML(ostream &io,  CifString dType);
static char *_get_attribute_value_where(CifFileObj *fobj, const char *blockId, const char *category, 
					const char *attributeA, const char *attributeB, const char *valB);

//private const
//const int CifSchemaMap::_MAX_NAME_LENGTH =80;
const int CifSchemaMap::_MAX_LINE_LENGTH =130;
int CifSchemaMap::_RCSBEXTENSIONS  =TRUE;

const int CifSchemaMap::_TYPE_CODE_INT        = 1;
const int CifSchemaMap::_TYPE_CODE_FLOAT      = 2;
const int CifSchemaMap::_TYPE_CODE_STRING     = 3;
const int CifSchemaMap::_TYPE_CODE_TEXT       = 4;
const int CifSchemaMap::_TYPE_CODE_DATETIME   = 5;
const int CifSchemaMap::_TYPE_CODE_BIGINT     = 6;

const int CifSchemaMap::_SERVER_TYPE_SYBASE   = 1;
const int CifSchemaMap::_SERVER_TYPE_MYSQL    = 2;
const int CifSchemaMap::_SERVER_TYPE_ORACLE   = 3;
const int CifSchemaMap::_SERVER_TYPE_DB2      = 4;
const long CifSchemaMap::_MAXFILESIZE = 2000000000;
//public const
const int CifSchemaMap::MODE_SQL=1;
const int CifSchemaMap::MODE_BCP=2;
const int CifSchemaMap::MODE_XML=3;

const int CifSchemaMap::_SCRIPT_ONLY      = 2;
const int CifSchemaMap::_DATA_ONLY        = 0;
const int CifSchemaMap::_DATA_PLUS_SCRIPT = 1;



long long CifSchemaMap::pdbIdHash(const char *id) 
{
  long long ival, base, base1;

  int i,j;
  int id1[5];
  const char *list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

  ival = (long long) 0;
  base = (long long) strlen(list);
  if ( id == NULL  ||  (strlen(id) <  4) ) return ival;

  //  if (_verbose) _log << "pdbidhash value " << id << " len " << strlen(id) << " base " << base << endl;

  if (strlen(id) == 4) {
    base1 = (long long) 1;
    for (i = 3, j= 0; i >= 0; i--) {
      
      if (i != 3) base1 = base1*base;
      
      for (j=0; j<base; j++) {
	
	//      if (_verbose) _log << "pdbidhash i " <<  i << " j " << j << " id[i] " << id[i] << endl;
	
	if (id[i] == list[j]) {
	  ival = ival + base1 * j;
	  break;
	}
      }
      //   if (_verbose) _log << "pdbidhash i " << i << " ival " << ival << " j " << j 
      //			 << " id[i] " << id[i] << " base1 " << base1 << endl; 
    }
    //if (_verbose) _log << "pdbidhash " << ival << endl; 
    ival = ival * 4000000;
    //if (_verbose) _log << "pdbidhash * 4M " << ival << endl; 

  } else  if (strlen(id) == 7) {
    i=0;
    for (j = 3; j < 7; j++) {
      id1[i] = id[j];
      i++;
    }
    id1[i]='\0';

    base1 = (long long) 1;
    for (i = 3, j= 0; i >= 0; i--) {
      
      if (i != 3) base1 = base1*base;
      
      for (j=0; j<base; j++) {
	
	//      if (_verbose) _log << "pdbidhash i " <<  i << " j " << j << " id1[i] " << id1[i] << endl;
	
	if (id1[i] == list[j]) {
	  ival = ival + base1 * j;
	  break;
	}
      }
      //   if (_verbose) _log << "pdbidhash i " << i << " ival " << ival << " j " << j 
      //			 << " id1[i] " << id1[i] << " base1 " << base1 << endl; 
    }
    //if (_verbose) _log << "pdbidhash " << ival << endl; 
    ival = ival * 4000000;
    //if (_verbose) _log << "pdbidhash * 4M " << ival << endl; 


  } else if (strlen(id) == 10 ) {
    base =10;
    base1 = (long long) 1;
    for (i = 9, j= 0; i >= 4; i--) {
      
      if (i != 9) base1 = base1*base;
      
      for (j=0; j<base; j++) {
	
	//      if (_verbose) _log << "pdbidhash i " <<  i << " j " << j << " id[i] " << id[i] << endl;
	
	if (id[i] == list[j]) {
	  ival = ival + base1 * j;
	  break;
	}
      }
      // if (_verbose) _log << "pdbidhash i " << i << " ival " << ival << " j " << j 
      //		 << " id[i] " << id[i] << " base1 " << base1 << endl; 
    }
    ival = ival + 2000000;
    //if (_verbose) _log << "pdbidhash " << ival << endl; 
    ival = ival * 4000000;
    //if (_verbose) _log << "pdbidhash * 4M " << ival << endl; 

  } else if (strlen(id) == 6 ) { // NDB ids without pdb ids.
    base = (long long) strlen(list);
    base1 = (long long) 1;
    for (i = 5, j= 0; i >= 0; i--) {
      
      if (i != 5) base1 = base1*base;
      
      for (j=0; j<base; j++) {
	
	//      if (_verbose) _log << "pdbidhash i " <<  i << " j " << j << " id[i] " << id[i] << endl;
	
	if (id[i] == list[j]) {
	  ival = ival + base1 * j;
	  break;
	}
      }
      // if (_verbose) _log << "pdbidhash i " << i << " ival " << ival << " j " << j 
      //		 << " id[i] " << id[i] << " base1 " << base1 << endl; 
    }
    ival = ival + 2000000;
    //if (_verbose) _log << "pdbidhash " << ival << endl; 
    ival = ival * 2000000;
    //if (_verbose) _log << "pdbidhash * 4M " << ival << endl; 


  } 
  return (ival);
}


void CifSchemaMap::Clear() {
   
  _schemaFile    = NULL;
  _schemaFileOdb = NULL;
  _fobjS         = NULL;
  _tableSchema   = NULL;
  _attribSchema  = NULL;
  _schemaMap     = NULL;
  _mapConditions = NULL;
  _verbose       = 0;
  _blockName     = NULL;
  _path          = NULL;
  _dbName        = NULL;
  _dbUser        = NULL;
  _dbMgr         = NULL;
  _rowSeparator  = NULL;
  _fieldSeparator = NULL;
  _cmdTerm = NULL;
  memset(_INPUT_FILE, 0, 512);
}

void CifSchemaMap::Reset() {
  if (_schemaFile)       delete[] _schemaFile;
  if (_schemaFileOdb)    delete[] _schemaFileOdb;
  if (_blockName)        delete[] _blockName;
  if (_path)             delete[] _path;
  if (_dbName)           delete[] _dbName;
  if (_dbUser)           delete[] _dbUser;
  if (_dbMgr)            delete[] _dbMgr;
  if (_fobjS)            delete _fobjS;
  if (_fieldSeparator)   delete[] _fieldSeparator;
  if (_rowSeparator)     delete[] _rowSeparator;
  if (_cmdTerm)          delete[] _cmdTerm;
  if (_schemaMap) delete _schemaMap;
/*
  if (_tableSchema) delete _tableSchema;
  if (_mapConditions) delete _mapConditions;
  if (_tableAbbrev) delete _tableAbbrev;
  if (_attributeAbbrev) delete _attributeAbbrev;
*/
}

void CifSchemaMap::_OpenLog(const char *logName)
{
  if (_verbose && logName) _log.open(logName,ios::out|ios::trunc);
}



CifSchemaMap::CifSchemaMap(const char * schemaFile, const char * schemaFileOdb, int verbose) {

  char *diags=NULL;

  Clear();
  _compatibilityMode=1;
  _hashMode=1;
  _verbose = verbose;
  _serverType = _SERVER_TYPE_SYBASE;
  
  // Both input files are required so we must bail if these are not specified.
  if (!schemaFile || !schemaFileOdb ) return;

 _schemaFile = new char[strlen(schemaFile)+1];
  strcpy(_schemaFile, schemaFile);

 _schemaFileOdb = new char[strlen(schemaFileOdb)+1];
  strcpy(_schemaFileOdb, schemaFileOdb);

  // Set default values  ...  These can be overridden if necessary .
 _path = new char[10];
  strcpy(_path, "");

 _blockName = new char[10];
  strcpy(_blockName,"loadable");

 _dbName = new char[5];
  strcpy(_dbName,"msd1");

 _dbUser = new char[10];
  strcpy(_dbUser,"rcsbuser");

 _dbMgr  = new char[10];
  strcpy(_dbMgr,"rcsbmgr");

  _fieldSeparator = new char[2];
  _fieldSeparator[0]='\t';   _fieldSeparator[1]='\0';

  _rowSeparator = new char[2];
  _rowSeparator[0]='\n';   _rowSeparator[1]='\0';

  _cmdTerm = new char[5];
  _cmdTerm[0]='\n'; _cmdTerm[1]='g'; _cmdTerm[2]='o'; _cmdTerm[3]='\n';   _cmdTerm[4]='\0';

  if (_verbose) {
    char *logName = new char[strlen(_path) + strlen(_LOG_FILE) + 1];
    strcpy(logName,_path);
    strcat(logName,_LOG_FILE);
    _OpenLog(logName);
    if (logName) delete logName;
  }

  //
  //----------------------------------------------------------------------
  //              Read schema and map data file ... 
  //
  _fobjS = new CifFileObj( _schemaFileOdb, WRITE_MODE, _MAX_LINE_LENGTH, "?",_verbose);
  _fobjS->Read(_schemaFile, diags);
  if (diags) {
    if (_verbose) _log << " Diagnostics [" << strlen(diags) << "] " << diags << endl;
    delete diags;
  }
  
  _fobjS->CloseFile();
  delete _fobjS;
  _fobjS = new CifFileObj(_schemaFileOdb,    READ_MODE, _MAX_LINE_LENGTH, "?", _verbose);

  if (_verbose) {
    if (_fobjS) {
      _log << "Opened schema object file" << endl;
      _fobjS->Write("/var/tmp/XXXX.cif");
    } else
      _log << "Open failed for object file" << endl;
  }

  _AssignAttribIndices();

}



CifSchemaMap::CifSchemaMap(const char * schemaFile, const char * schemaFileOdb, 
			   const char * path, int verbose) {

  char *diags=NULL;

  Clear();
  _verbose = verbose;
  _compatibilityMode=1;
  _hashMode=1;
  _serverType = _SERVER_TYPE_SYBASE;
  // Both input files are required so we must bail if these are not specified.
  if (!schemaFile || !schemaFileOdb ) return;


  if (path && strlen(path)) {
    _path = new char[strlen(path)+1];
    strcpy(_path, path);
  } else {
    _path = new char[10];
    strcpy(_path, "");
  }

 _schemaFile = new char[strlen(schemaFile)+1];
  strcpy(_schemaFile, schemaFile);

 _schemaFileOdb = new char[strlen(schemaFileOdb)+1];
  strcpy(_schemaFileOdb, schemaFileOdb);

 _blockName = new char[10];
  strcpy(_blockName,"loadable");

 _dbName = new char[5];
  strcpy(_dbName,"msd1");

 _dbUser = new char[10];
  strcpy(_dbUser,"rcsbuser");

 _dbMgr = new char[10];
  strcpy(_dbMgr,"rcsbmgr");

  _fieldSeparator = new char[2];
  _fieldSeparator[0]='\t';   _fieldSeparator[1]='\0';

  _rowSeparator = new char[2];
  _rowSeparator[0]='\n';   _rowSeparator[1]='\0';

  _cmdTerm = new char[5];
  _cmdTerm[0]='\n'; _cmdTerm[1]='g'; _cmdTerm[2]='o'; _cmdTerm[3]='\n';   _cmdTerm[4]='\0';

  if (_verbose) {
    char *logName = new char[strlen(_path) + strlen(_LOG_FILE) + 1];
    strcpy(logName,_path);
    strcat(logName,_LOG_FILE);
    _OpenLog(logName);
    if (logName) delete logName;
  }

  //
  //----------------------------------------------------------------------
  //              Read schema and map data file ... 
  //
  _fobjS = new CifFileObj( _schemaFileOdb, WRITE_MODE, _MAX_LINE_LENGTH, "?",_verbose);
  _fobjS->Read(_schemaFile, diags);
  if (diags) {
    if (_verbose) _log << " Diagnostics [" << strlen(diags) << "] " << diags << endl;
    delete diags;
  }
  
  _fobjS->CloseFile();
  delete _fobjS;
  _fobjS = new CifFileObj(_schemaFileOdb,    READ_MODE, _MAX_LINE_LENGTH, "?", _verbose);

  if (_verbose) {
    if (_fobjS) {
      _log << "Using alternate constructor" << endl;
      _log << "Opened schema object file XXXX.cif" << endl;
      _fobjS->Write("/var/tmp/XXXX.cif");
    } else
      _log << "Open failed for object file" << endl;
  }

  _AssignAttribIndices();

}



CifSchemaMap::CifSchemaMap(const char * schemaFileOdb, int verbose, const char *path) {


  Clear();
  _verbose = verbose;
  _compatibilityMode=1;
  _hashMode=1;
  _serverType = _SERVER_TYPE_SYBASE;
  // Both input files are required so we must bail if these are not specified.
  if (!schemaFileOdb) return;

  if (path && strlen(path)) {
    _path = new char[strlen(path)+1];
    strcpy(_path, path);
  } else {
    _path = new char[10];
    strcpy(_path, "");
  }

 _schemaFileOdb = new char[strlen(schemaFileOdb)+1];
  strcpy(_schemaFileOdb, schemaFileOdb);

 _blockName = new char[10];
  strcpy(_blockName,"loadable");

 _blockName = new char[10];
  strcpy(_blockName,"loadable");


 _dbName = new char[5];
  strcpy(_dbName,"msd1");

 _dbUser = new char[10];
  strcpy(_dbUser,"rcsbuser");

 _dbMgr = new char[10];
  strcpy(_dbMgr,"rcsbmgr");

  _fieldSeparator = new char[2];
  _fieldSeparator[0]='\t';   _fieldSeparator[1]='\0';
  
  _rowSeparator = new char[2];
  _rowSeparator[0]='\n';   _rowSeparator[1]='\0';

  _cmdTerm = new char[5];
  _cmdTerm[0]='\n'; _cmdTerm[1]='g'; _cmdTerm[2]='o'; _cmdTerm[3]='\n';   _cmdTerm[4]='\0';

  if (_verbose) {
    char *logName = new char[strlen(_path) + strlen(_LOG_FILE) + 1];
    strcpy(logName,_path);
    strcat(logName,_LOG_FILE);
    _OpenLog(logName);
    if (logName) delete logName;
    _log << "Starting with ODB schema map " <<  _schemaFileOdb << endl;
  }

  _fobjS = new CifFileObj(_schemaFileOdb,    READ_MODE, _MAX_LINE_LENGTH, "?",_verbose);
  if (_verbose) {
    if (_fobjS) {
      _log << "Opened schema object file" << endl;
      _fobjS->Write("/var/tmp/XXXX.cif");
    } else
      _log << "Open failed for object file" << endl;
  }
  _AssignAttribIndices();

  if (_verbose) _log << "Indices assigned on schema object file" << endl;

}


void CifSchemaMap::SetPath(const char *path) {

  if (!path || !strlen(path)) return;

  if (_path) delete _path;
 _path = new char[strlen(path)+1];
  strcpy(_path,path);
}

void CifSchemaMap::SetCompatibilityMode(int mode) {
  // compatibility mode 2 adds Structure_ID to table/columninfo tables
  //   for very old ndb apps.  jdw
  _compatibilityMode=mode;
}

void CifSchemaMap::SetHashMode(int mode) {
  _hashMode=mode;
}


char *CifSchemaMap::GetCommandPath() {

 char * path = new char[strlen(_path)+ strlen(_COMMAND_FILE) + 1];
 strcpy(path,_path);
 strcat(path,_COMMAND_FILE);
 return (path);
}


void CifSchemaMap::SetDatabaseName(const char *dbName) {

  if (!dbName || !strlen(dbName)) return;

  if (_dbName) delete[] _dbName;
 _dbName = new char[strlen(dbName)+1];
  strcpy(_dbName,dbName);
}


void CifSchemaMap::SetDatabaseUser(const char *dbUser) {
  if (!dbUser || !strlen(dbUser)) return;

  if (_dbUser) delete _dbUser;
 _dbUser = new char[strlen(dbUser)+1];
  strcpy(_dbUser,dbUser);
}

void CifSchemaMap::SetDatabaseMgr(const char *dbMgr) {
  if (!dbMgr || !strlen(dbMgr)) return;

  if (_dbMgr) delete _dbMgr;
 _dbMgr = new char[strlen(dbMgr)+1];
  strcpy(_dbMgr,dbMgr);
}


void CifSchemaMap::SetServerType(const char *server) {
  if (!server || !strlen(server)) return;

  if (!strcmp(server,"sybase")) {
    _serverType = _SERVER_TYPE_SYBASE;
  } else   if (!strcmp(server,"mysql")) {
    _serverType = _SERVER_TYPE_MYSQL;
    if (_cmdTerm) delete[] _cmdTerm;
    _cmdTerm = new char[2];
    _cmdTerm[0]=';'; _cmdTerm[1]='\0';

  } else if (!strcmp(server,"oracle")) {
    _serverType = _SERVER_TYPE_ORACLE;
    if (_cmdTerm) delete[] _cmdTerm;
    _cmdTerm = new char[2];
    _cmdTerm[0]=';'; _cmdTerm[1]='\0';
  } else if (!strcmp(server,"db2")) {
    _serverType = _SERVER_TYPE_DB2;
    if (_cmdTerm) delete[] _cmdTerm;
      _cmdTerm = new char[2];
      _cmdTerm[0]=';'; _cmdTerm[1]='\0';
  }

}


void CifSchemaMap::SetFieldSeparator(const char *fieldSeparator) {

  if (!fieldSeparator || !strlen(fieldSeparator)) return;

  if (_fieldSeparator) delete[] _fieldSeparator;
 _fieldSeparator = new char[strlen(fieldSeparator)+1];
  strcpy(_fieldSeparator,fieldSeparator);
}


void CifSchemaMap::SetRowSeparator(const char *rowSeparator) {

  if (!rowSeparator || !strlen(rowSeparator)) return;

  if (_rowSeparator) delete[] _rowSeparator;
 _rowSeparator = new char[strlen(rowSeparator)+1];
  strcpy(_rowSeparator,rowSeparator);
}



void CifSchemaMap::_AssignAttribIndices() {
  int i;
  _tableSchema     = _fobjS->GetTablePtr("rcsb_schema","rcsb_table");
  _attribSchema    = _fobjS->GetTablePtr("rcsb_schema","rcsb_attribute_def");
  _schemaMap       = _fobjS->GetTablePtr("rcsb_schema_map","rcsb_attribute_map");
  _mapConditions   = _fobjS->GetTablePtr("rcsb_schema_map","rcsb_map_condition");
  _tableAbbrev     = _fobjS->GetTablePtr("rcsb_schema","rcsb_table_abbrev");
  _attributeAbbrev = _fobjS->GetTablePtr("rcsb_schema","rcsb_attribute_abbrev");

  _cInTATableName     = _tableAbbrev->GetColumnIndex("table_name");
  _cInTATableNameAbbrev   = _tableAbbrev->GetColumnIndex("table_abbrev");
  if (_cInTATableName< 0 || _cInTATableNameAbbrev < 0 ) {
    if (_verbose) _log << "Table abbreviations incomplete" << endl;
    return;
  }

  _cInAATableName         = _attributeAbbrev->GetColumnIndex("table_name");
  _cInAAAttributeName     = _attributeAbbrev->GetColumnIndex("attribute_name");
  _cInAAAttributeNameAbbrev   = _attributeAbbrev->GetColumnIndex("attribute_abbrev");
  if ( _cInAATableName < 0 || _cInAAAttributeName < 0 || _cInAAAttributeNameAbbrev < 0 ) {
    if (_verbose) _log << "Attribute abbreviations incomplete" << endl;
    return;
  }

  _cInTSTableName  = _tableSchema->GetColumnIndex("table_name");
  _cInTSGroupName  = _tableSchema->GetColumnIndex("group_name");
  if (_cInTSTableName < 0 || _cInTSGroupName < 0 ) {
    if (_verbose) _log << "Table schema table incomplete" << endl;
    return;
  }


  _cInASTableName     = _attribSchema->GetColumnIndex("table_name");
  _cInASAttributeName = _attribSchema->GetColumnIndex("attribute_name");
  _cInASDataType      = _attribSchema->GetColumnIndex("data_type");
  _cInASIndexFlag     = _attribSchema->GetColumnIndex("index_flag");
  _cInASNullFlag      = _attribSchema->GetColumnIndex("null_flag");
  _cInASWidth         = _attribSchema->GetColumnIndex("width");
  _cInASPrecision     = _attribSchema->GetColumnIndex("precision");

  if (_cInASTableName < 0 || _cInASAttributeName < 0 || _cInASDataType < 0 ||
      _cInASIndexFlag < 0 || _cInASNullFlag < 0 || _cInASWidth < 0 ||  _cInASPrecision < 0) {
    if (_verbose) _log << "Attribute schema table incomplete" << endl;
    return;
  }

  //

  _cInSMTargetTableName     = _schemaMap->GetColumnIndex("target_table_name");
  _cInSMTargetAttributeName = _schemaMap->GetColumnIndex("target_attribute_name");
  _cInSMSourceItemName      = _schemaMap->GetColumnIndex("source_item_name");
  _cInSMConditionId         = _schemaMap->GetColumnIndex("condition_id");
  _cInSMFunctionId          = _schemaMap->GetColumnIndex("function_id");
   if ( _cInSMTargetTableName < 0 ||   _cInSMTargetAttributeName < 0 || 
	_cInSMSourceItemName  < 0 ||  _cInSMConditionId < 0 || _cInSMFunctionId < 0) {
    if (_verbose) _log << "Schema map table incomplete" << endl;
    return;
  }

  _cInMCConditionId    = _mapConditions->GetColumnIndex("condition_id");
  _cInMCAttributeName  = _mapConditions->GetColumnIndex("attribute_name");
  _cInMCAttributeValue = _mapConditions->GetColumnIndex("attribute_value");
  if (_cInMCConditionId < 0 || _cInMCAttributeName < 0 || _cInMCAttributeValue < 0) {
    if (_verbose) _log << "Map condition table incomplete" << endl;
    return;
  }
  //
  // Check that all schema attributes have a CIF mapping....
  //
  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  int errCode;
  ReVarCifArray<CifString> qcol, qval;    
  qcol.Clear(); qcol.Add("target_table_name"); qcol.Add("target_attribute_name");

  for (i=0; i < _attribSchema->GetNumRows(); i++) {
    row = _attribSchema->GetRow(i);
    if (row) {
      qval.Clear();
      qval.Add((*row)[_cInASTableName]);
      qval.Add((*row)[_cInASAttributeName]);
      delete row;
      row = NULL;
    } else {
      continue;
    }

    ir = _schemaMap->Search(qval, qcol, errCode);
    if (ir && ir->Length() > 0) {
      delete ir;
      continue;
    } else {
      if ( !strcmp(qval[0].Text(),"tableinfo") || !strcmp(qval[0].Text(),"columninfo"))
	continue;
      else
	cerr << "No CIF mapping for " << qval[0].Text() << "."  <<qval[1].Text() << endl;
    }
  }
  
  //
  CifString cs1, cs2, cs3;
  //

  ISTable * t = new ISTable("rcsb_attribute_map1");
  //  ReVarCifArray<CifString> *trow = NULL;
  CifString empty("");
  int jrow = 0;
  t->AddColumn("target_table_name", TRUE);
  t->AddColumn("target_attribute_name", TRUE);
  t->AddColumn("source_item_name", TRUE);
  t->AddColumn("condition_id", TRUE);
  t->AddColumn("function_id", TRUE);
  
  qcol.Clear(); qcol.Add("table_name"); qcol.Add("attribute_name");

  for (i=0; i < _schemaMap->GetNumRows(); i++) {
        if (row) {
          delete row;
          row = NULL;
        }
    row = _schemaMap->GetRow(i);
    if (row) {
      qval.Clear();
      qval.Add((*row)[_cInSMTargetTableName]);
      qval.Add((*row)[_cInSMTargetAttributeName]);

    } else {
      continue;
    }
#if 0
    // JDW test 
    cs1.Clear(); cs1.Copy((*row)[_cInSMTargetTableName]);
    cs2.Clear(); cs2.Copy((*row)[_cInSMTargetAttributeName]);
    _GetTableNameAbbrev(cs3, cs1);
    cerr << "table " << cs1.Text() << " abbrev " << cs3.Text() << endl;

    _GetAttributeNameAbbrev(cs3, cs1, cs2);
    cerr << "table " << cs1.Text() << " attrib " << cs2.Text() << " abbrev " << cs3.Text() << endl;
#endif

    //
    ir = _attribSchema->Search(qval, qcol, errCode);
    if (ir && ir->Length() > 0) {
#if 0
      t->AddRow();
      trow = new ReVarCifArray<CifString>;
      for (j=0; j < 5; j++) {
	trow->Add(empty.Text());
      }
      for (j=0; j < 5; j++) {
	(*trow)[j].Copy( (*row)[j].Text() );
      }
      t->FillRow( *trow, jrow);
      delete trow;
#else
      t->AddRow();
      t->FillRow( *row, jrow);
#endif
      jrow++;
      delete ir;
      continue;
    } else {
      //      cerr << "In " << _INPUT_FILE << ": " << "No schema correspondence for " << "_"<< qval[0].Text() 
      //	   << "."  <<qval[1].Text() << endl;
      if (_verbose) _log << "No schema correspondence for " 
			 << (*row)[_cInSMSourceItemName].Text() 
			 << endl;

    }

  }
        if (row) {
          delete row;
          row = NULL;
        }
  _schemaMap = t;
}


void CifSchemaMap::_GetTableNameAbbrevXML(CifString &abbrev, CifString target)
{
  int len,i,j;
  char name[_MAX_NAME_LENGTH];
  char tmp[_MAX_NAME_LENGTH];

  strcpy(name,target.Text());
  len=strlen(name);
  memset(tmp,'\0',_MAX_NAME_LENGTH);

  j=0;
  for (i=0; i < len; i++) {
    if (name[i] == '[' || name[i] == ']' || name[i] == '%' || name[i] == '<' || name[i] == '>') 
      continue;
    else { 
      tmp[j]=name[i]; j++;
    }
  }
  tmp[j] = '\0';
  abbrev.Clear(); abbrev.Copy(tmp);
  return;
}

void CifSchemaMap::_GetAttributeNameAbbrevXML(CifString &abbrev, CifString targetTable, CifString targetAttribute)
{
  int len,i,j;
  char name[_MAX_NAME_LENGTH];
  char tmp[_MAX_NAME_LENGTH];

  strcpy(name,targetAttribute.Text());
  len=strlen(name);
  memset(tmp,'\0',_MAX_NAME_LENGTH);

  j=0;
  for (i=0; i < len; i++) {
    if (name[i] == '[' || name[i] == ']' || name[i] == '%' || name[i] == '<' || name[i] == '>') 
      continue;
    else { 
      tmp[j]=name[i]; j++;
    }
  }
  tmp[j] = '\0';
  abbrev.Clear(); abbrev.Copy(tmp);
  return;
}


void CifSchemaMap::_GetTableNameAbbrev(CifString &abbrev, CifString target)
{

  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  int errCode;
  ReVarCifArray<CifString> qcol, qval;    

  abbrev.Clear(); abbrev.Copy(target);
  
  qcol.Clear(); qcol.Add("table_name");
  qval.Clear(); qval.Add(target);
  ir = _tableAbbrev->Search(qval, qcol, errCode);

  if ( !ir || ir->Length() <= 0) return;
  row = _tableAbbrev->GetRow((*ir)[0]);
  abbrev.Clear();
  abbrev.Copy((*row)[_cInTATableNameAbbrev]);
  delete ir;
  delete row;
  return;
}

void CifSchemaMap::_GetAttributeNameAbbrev(CifString &abbrev, CifString targetTable, CifString targetAttribute)
{

  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;

  int errCode;
  ReVarCifArray<CifString> qcol, qval;    
  abbrev.Clear(); abbrev.Copy(targetAttribute);

  qcol.Clear(); qcol.Add("table_name"); qcol.Add("attribute_name");
  qval.Clear(); qval.Add(targetTable); qval.Add(targetAttribute);
  ir = _attributeAbbrev->Search(qval, qcol, errCode);

  if ( !ir || ir->Length() <= 0) return;
  row = _attributeAbbrev->GetRow((*ir)[0]);
  abbrev.Clear();
  abbrev.Copy((*row)[_cInAAAttributeNameAbbrev]);
  delete ir;
  delete row;
  return;
}


void CifSchemaMap::LoadFile(const char *inpFile, int mode, int opFlag) 
{
  char *diags = NULL;
  const char *blockName = "loadable";
  char templateFileName[9] = "./XXXXXX";
  char tObjFile[9], tLoadFile[9];
  char *tempName;
  char *tempHash=NULL, *tempHashAlt=NULL;
  if (inpFile == NULL || strlen(inpFile) == 0)  return;
  strncpy(_INPUT_FILE,inpFile,511);

  strcpy(tLoadFile, templateFileName);
  mkstemp(tLoadFile);
  if (_verbose) _log << "Creating output object file " <<  tLoadFile << " block " << blockName << endl;
  CifFileObj *fobjW = new CifFileObj(tLoadFile, WRITE_MODE, _MAX_LINE_LENGTH, "?",_verbose);  
  _CreateTables(fobjW,blockName);
  if (_verbose) _log << "Done with _CreateTable()" << endl;

  if (opFlag != _SCRIPT_ONLY) {
    strcpy(tObjFile, templateFileName);
    mkstemp(tObjFile);
    CifFileObj *fobjR = new CifFileObj(tObjFile, WRITE_MODE, _MAX_LINE_LENGTH, "?",_verbose);  
    if (_verbose) _log << "Reading input file  " << inpFile << endl;
    fobjR->Read(inpFile,diags);
    if (diags) {
      if (_verbose) _log << " Diagnostics [" << strlen(diags) << "] " << diags << endl;
      delete diags;
    }
    fobjR->CloseFile();
    delete fobjR;
    
    //
    
    fobjR = new CifFileObj(tObjFile, READ_MODE, _MAX_LINE_LENGTH, "?",_verbose);  

    // 

    //JDW
    //    if (_verbose) fobjR->Write("datafile-test-2.ocif");
    
    for (int i=0; i < fobjR->GetNumBlocks(); i++) {
      tempName=fobjR->GetBlockName(i);
      if (tempName == NULL) {
	cerr << "Skipping unnamed block " << endl;
	continue;
      }
      if (_verbose) _log << "Loading block " << i+1 << " " << tempName<< endl;
      
      if (_hashMode == 1) { 
	tempHash  = _get_attribute_value_where(fobjR, tempName, "database_2", "database_code", 
					       "database_id", "PDB");
	tempHashAlt  = _get_attribute_value_where(fobjR, tempName, "database_2", "database_code", 
					       "database_id", "NDB");
	if (tempHash) {
	  strcpy(_HASH_ID,tempHash);
          delete ( tempHash); 
          tempHash = NULL;
	  if (tempHashAlt) { 
	    delete ( tempHashAlt); 
	    tempHash = NULL; 
	  }
	} else if (tempHashAlt) {
	  strcpy(_HASH_ID,tempHashAlt);
          delete ( tempHashAlt); 
          tempHashAlt = NULL;
	} else {
	  cerr << "Skipping block with no hashable ID " << tempName <<endl;
	  continue;
	}

      } else {
	strcpy(_HASH_ID,tempName);
      }
      if (_verbose) _log << "Hash id for block " << i+1 << " " << tempName << " is " << _HASH_ID <<endl;
      _LoadBlock(fobjR, tempName, fobjW, blockName);
      delete tempName;
    }
    if (_verbose) _log << "Done with _LoadBlock()" << endl;
    fobjR->CloseFile();
    delete fobjR;  
    remove(tObjFile);
  }

  if (mode == MODE_BCP) {
    if (opFlag != _SCRIPT_ONLY) _UpdateBCP(fobjW, 1);
    if (opFlag != _DATA_ONLY) _WriteScriptBCP();
    if (opFlag != _DATA_ONLY && _serverType == _SERVER_TYPE_ORACLE)  _WriteOracleControlFiles(1);
    if (opFlag != _DATA_ONLY && _serverType == _SERVER_TYPE_DB2)     _WriteDB2ControlFiles();
    if (opFlag != _DATA_ONLY && _serverType == _SERVER_TYPE_MYSQL)   _WriteMysqlLoadFile(1);
    if (opFlag != _DATA_ONLY && (_serverType == _SERVER_TYPE_ORACLE || _serverType == _SERVER_TYPE_DB2 ||
                       _serverType == _SERVER_TYPE_SYBASE))  _UpdateIndicesSQL();
    
  }  else if (mode == MODE_SQL) {

    _UpdateSQL(fobjW, 1);
    if (opFlag != _DATA_ONLY) _WriteScriptSQL();

  }  else if (mode == MODE_XML) {
    _UpdateXML(fobjW, 0);
  }

  fobjW->CloseFile();
  delete fobjW;

  remove(tLoadFile);

}



void CifSchemaMap::LoadFileObj(char *inpFileObj, int mode) 
{

  //  char *blockName = "loadable";
  char templateFileName[9] = "./XXXXXX";
  char tLoadFile[9];
  int opFlag=_DATA_PLUS_SCRIPT;
  

  if (!inpFileObj) return;
  strncpy(_INPUT_FILE,inpFileObj,511);

  strcpy(tLoadFile, templateFileName);
  mkstemp(tLoadFile);
  //
  if (_verbose) _log << "Creating output object file " <<  tLoadFile << " block " << _blockName << endl;
  CifFileObj *fobjW = new CifFileObj(tLoadFile, WRITE_MODE, _MAX_LINE_LENGTH, "?",_verbose);  
  _CreateTables(fobjW,_blockName);
  if (_verbose) _log << "Done with _CreateTable()" << endl;

  CifFileObj *fobjR = new CifFileObj(inpFileObj, READ_MODE, _MAX_LINE_LENGTH, "?",_verbose);  
  //  fobjR->Write("test-datafile.ocif");

  
  for (int i=0; i < fobjR->GetNumBlocks(); i++) {
    if (_verbose) _log << "Loading block " << i+1 << " " << fobjR->GetBlockName(i) << endl;
    _LoadBlock(fobjR, fobjR->GetBlockName(i), fobjW, _blockName);
  }
  if (_verbose) _log << "Done with _LoadBlock()" << endl;

  //  fobjW->Write("test-loadable.ocif");

  if (mode == MODE_BCP) {
    _UpdateBCP(fobjW, 1);
    _WriteScriptBCP();
    if (_serverType == _SERVER_TYPE_ORACLE)  _WriteOracleControlFiles(0);
    if (_serverType == _SERVER_TYPE_DB2)     _WriteDB2ControlFiles();
    if (opFlag != _DATA_ONLY && _serverType == _SERVER_TYPE_MYSQL)   _WriteMysqlLoadFile(1);
    if (opFlag != _DATA_ONLY && (_serverType == _SERVER_TYPE_ORACLE || _serverType == _SERVER_TYPE_DB2 ||
                       _serverType == _SERVER_TYPE_SYBASE))  _UpdateIndicesSQL();

  }  else if (mode == MODE_SQL) {
    _UpdateSQL(fobjW, 1);
    if (opFlag != _DATA_ONLY) _WriteScriptSQL();
  }  else if (mode == MODE_XML) {
    _UpdateXML(fobjW, 0);
  }

  fobjW->CloseFile();
  fobjR->CloseFile();
  delete fobjR;  
  delete fobjW;
  remove(tLoadFile);  
}




void CifSchemaMap::LoadFileObj(CifFileObj *fobjR, int mode) 
{

  char templateFileName[9] = "./XXXXXX";
  char tLoadFile[9];
  int opFlag=_DATA_PLUS_SCRIPT;

  strcpy(tLoadFile, templateFileName);
  mkstemp(tLoadFile);

  if (!fobjR) return;

  //
  if (_verbose) _log << "Creating output object file " <<  tLoadFile << " block " << _blockName << endl;
  CifFileObj *fobjW = new CifFileObj(tLoadFile, WRITE_MODE, _MAX_LINE_LENGTH, "?",_verbose);  
  _CreateTables(fobjW,_blockName);
  if (_verbose) _log << "Done with _CreateTable()" << endl;

  for (int i=0; i < fobjR->GetNumBlocks(); i++) {
    if (_verbose) _log << "Loading block " << i+1 << " " << fobjR->GetBlockName(i) << endl;
    _LoadBlock(fobjR, fobjR->GetBlockName(i), fobjW, _blockName);
  }


  if (mode == MODE_BCP) {
    _UpdateBCP(fobjW, 1);
    _WriteScriptBCP();
    if (_serverType == _SERVER_TYPE_ORACLE)  _WriteOracleControlFiles(0);
    if (_serverType == _SERVER_TYPE_DB2)  _WriteDB2ControlFiles();
    if (opFlag != _DATA_ONLY && _serverType == _SERVER_TYPE_MYSQL)   _WriteMysqlLoadFile(1);
    if (opFlag != _DATA_ONLY && (_serverType == _SERVER_TYPE_ORACLE || _serverType == _SERVER_TYPE_DB2 ||
                       _serverType == _SERVER_TYPE_SYBASE))  _UpdateIndicesSQL();

  }  else if (mode == MODE_SQL) {
    _UpdateSQL(fobjW, 1);
    if (opFlag != _DATA_ONLY) _WriteScriptSQL();
  }  else if (mode == MODE_XML) {
    _UpdateXML(fobjW, 0);
  }

  fobjW->CloseFile();
  delete fobjW;
  remove(tLoadFile);  
}



void CifSchemaMap::_LoadBlock(CifFileObj *fobjR, const char *rBlockName,
			      CifFileObj *fobjW, const char *wBlockName) {
  // Create tables in the target schema ...

  int i, j, k, iskip;
  int nCols, errCode, ilen0=0, ierr;
  ReVarPCifArray<int> * ir = NULL;
  ReVarPCifArray<int> * irMap = NULL;

  ReVarCifArray<CifString> *cList = NULL;
  ReVarCifArray<CifString> *cNameMap = NULL;
  ReVarCifArray<CifString> *iNameMap = NULL;
  ReVarCifArray<CifString> *cIdMap   = NULL;
  ReVarCifArray<CifString> *fIdMap   = NULL;
  ReVarCifArray<CifString> ** dMap = NULL;
  int *indMap = NULL;
  ISTable *t = NULL;

  int iUpdate, iRow, minLen, maxLen, nColsMap;
  CifString empty(""), tmpS;
  ReVarCifArray<CifString> *row = NULL;

  //	
  // List of tables to updated in the current schema ... 
  ReVarCifArray<CifString> *tList =  _tableSchema->GetColumn(_cInTSTableName);

  ATTRIBINFO *aI = NULL;
  //
  //  
  //

  for (i=0; i < (int) tList->Length(); i++) {

    if (_verbose) {
      _log << " ---------------------------------------------------------------" << endl;
      _log << "Loading table "  << i+1 << " " << (*tList)[i].Text() << " of " 
	   << tList->Length() << endl;
    }


    t = fobjW->GetTablePtr(wBlockName,(*tList)[i].Text());
    if (!t) {
      if (_verbose) _log << "Missing output table " << (*tList)[i].Text() << endl;
      continue;
    }

    aI = _GetAttributeInfo(t);

    ir = _attribSchema->SearchColumn((*tList)[i],_cInASTableName, errCode);
    if ( !ir || ir->Length() <= 0) {
      if (aI)        delete[] aI;
      continue;
    }
    cList = _attribSchema->GetSubColumnByIndex(_cInASAttributeName, ir);
    nCols = cList->Length();
    if (_verbose) _log << "Schema defines " << nCols << " attributes " << endl;
    if (cList->Length() != ir->Length()) 
      if (_verbose) _log << "Length of column name list inconsistent " 
	   <<  " cList = "<< cList->Length() 
	   <<  " ir = " << ir->Length() << endl; 


    irMap       = _schemaMap->SearchColumn((*tList)[i], _cInSMTargetTableName, errCode);
    if ( !irMap || irMap->Length() <= 0) {
      if (_verbose) _log << "No mapped attributes for " << (*tList)[i].Text() << endl;      
      if (ir) delete ir;
      if (cList) delete cList;
      if (aI)        delete[] aI;
      continue; 
    } else {
      if (_verbose) _log << irMap->Length() << " mapped attributes for " 
			 << (*tList)[i].Text() << endl;      
    }

    cNameMap    = _schemaMap->GetSubColumnByIndex(_cInSMTargetAttributeName,irMap);
    iNameMap    = _schemaMap->GetSubColumnByIndex(_cInSMSourceItemName,irMap);
    cIdMap      = _schemaMap->GetSubColumnByIndex(_cInSMConditionId,irMap);
    fIdMap      = _schemaMap->GetSubColumnByIndex(_cInSMFunctionId,irMap);
    nColsMap    = cNameMap->Length();



    //
    // get index of mapped attributes in data table.
    //

    indMap = new int[nColsMap];
    ierr = 0;
    for (j=0; j < nColsMap; j++) {
      indMap[j] = t->GetColumnIndex((*cNameMap)[j].Text());
      if (indMap[j] < 0) {
	if (_verbose) _log << "Data table missing mapped attribute " 
			   << (*cNameMap)[j].Text() << endl; 
	ierr+=1;
      }
    }

    if (ierr)  {
      if (cList)     delete cList;
      if (cNameMap)  delete cNameMap;
      if (iNameMap)  delete iNameMap;
      if (cIdMap)    delete cIdMap;
      if (fIdMap)    delete fIdMap;
      if (ir)        delete ir;
      if (irMap)     delete irMap;
      if (indMap)    delete indMap;
      if (aI)        delete[] aI;
      continue;
    }

    if (_verbose) {
      _log << "Found "  << nColsMap << " attributes in schema map" << endl;
      for (j=0; j < nColsMap; j++) {
	_log << "Map entry " << j << " is schema attribute " << indMap[j] << " " 
	     << (*cNameMap)[j].Text() 
	     << " mapped to "  << (*iNameMap)[j].Text() 
	     << " " << (*cIdMap)[j].Text() << " " << (*fIdMap)[j].Text() << endl;
      }
    }


    //
    // Temporary space for extracted data isomorphorous with the table t ...
    //   
    //
    dMap  = new ReVarCifArray<CifString> *[nColsMap];
    for (j=0; j < nColsMap; j++) {
      dMap[j] = NULL;
    }

    
    iUpdate = 0;
    for (j=0; j < nColsMap; j++) {
      if (_verbose) _log << endl << "*" << endl 
			 << "Mapped attribute " << j <<  " is " << (*iNameMap)[j].Text() 
			 << " condition " << (*cIdMap)[j].Text() << " function  " 
			 << (*fIdMap)[j].Text() << " schema attribute index " << indMap[j] << endl;

      // jdw 16jun      if ( ! (*iNameMap)[j].Text() ||  ((*iNameMap)[j].Length() < 4) ) continue;

      iUpdate += _Search(fobjR, rBlockName, cNameMap, (*iNameMap)[j].Text(), 
			 (*cIdMap)[j].Text(), (*fIdMap)[j].Text(),
			 dMap, indMap, j);
    }


    if (iUpdate && dMap[0] && dMap[1]) {
      //
      // Supply key values in RCSB schema column 0 ...
      //
      if (_RCSBEXTENSIONS && (nColsMap > 1)) {
	ilen0 = dMap[0]->Length();
	//	ilen1 = dMap[1]->Length();
	minLen = ilen0;
	maxLen = ilen0;
	for (k=0; k < nColsMap; k++) {
	  if (!dMap[k]) continue;
	  if ((int) dMap[k]->Length() < minLen) minLen = dMap[k]->Length();
	  if ((int) dMap[k]->Length() > maxLen) maxLen = dMap[k]->Length();
	}
	
	//	if (_verbose) {
	//        _log << "   Length key column 0 " << dMap[0]->Length() << endl;
	//        _log << "   Length     column 1 " << dMap[1]->Length() << endl;
	//      }
	
	for (j=0; j < nColsMap; j++) {
	  if (aI[indMap[j]].iIndex != 1) continue;  // hack... if we are not an index.
	  if ( dMap[j] && (int) dMap[j]->Length() < maxLen && (int) dMap[j]->Length() > 0) {

	    if (_verbose) _log << " Extending  map column " << j 
			       << " with " << (*dMap[j])[0].Text()  << endl;

	    tmpS.Clear(); tmpS.Copy((*dMap[j])[0].Text());
	    for (k=dMap[j]->Length(); k < maxLen; k++) { 
	      dMap[j]->Add(tmpS.Text());
	    }
	  }
	}
	ilen0 = maxLen;
      } 
      //
      //  Check Result -- If the row length of result is not column consistent 
      //                  the mapping is problematic ...
      //

      minLen = ilen0;
      maxLen = ilen0;
      for (k=0; k < nColsMap; k++) {
	if (!dMap[k]) continue;
	if ((int) dMap[k]->Length() < minLen) minLen = dMap[k]->Length();
	if ((int) dMap[k]->Length() > maxLen) maxLen = dMap[k]->Length();
      }
      if (minLen != maxLen) {
	if (_verbose) {
	  _log << "Conflict in length min = " << minLen 
	       << " max = " << maxLen << endl;
	  _log << "Skipping table update update" << endl;

	}
	  cerr << "In " << _INPUT_FILE << ": " << "Skipping table update for " << (*tList)[i].Text() 
	       << " with inconsistent column lengths." << endl;

	for (j=0; j < nColsMap; j++) {
	  if (dMap[j]) delete dMap[j];
	}
	if (dMap)      delete dMap;
	if (indMap)    delete indMap;
	if (cList)     delete cList;
	if (cNameMap)  delete cNameMap;
	if (iNameMap)  delete iNameMap;
	if (cIdMap)    delete cIdMap;
	if (fIdMap)    delete fIdMap;
	if (ir)        delete ir;
	if (irMap)     delete irMap;
	if (aI)        delete[] aI;
	continue;
      }
      
      //
      //  Mapping OK, Update table ... 
      //
      if (_verbose) _log << " Table length = " << minLen << endl;
      ilen0 = minLen;

      for (k=0; k < ilen0;  k++) {

	//
	iskip=0;
	for (j=0; j < nColsMap; j++) {
	  if ( (aI[indMap[j]].iIndex || aI[indMap[j]].iNull) && 
	       (!dMap[j] || ((*dMap[j])[k].Length() == 0 ))) {
	    iskip = 1;
	    if (_verbose) _log << "Skipping row with NULL value in key attribute column " 
			       << indMap[j] << endl;
	    cerr  << "In " << _INPUT_FILE << ": "  
		  << "Skipping row in " << (*tList)[i].Text() 
		  << " with NULL value in key column " 
			       << indMap[j] << endl;
	    break;
	  }
	}
	if (iskip) continue; 
	    
	iRow = t->GetNumRows();
	if (_verbose) _log << "Updating " << (*tList)[i].Text() 
			   << " row " << iRow << endl;

	t->AddRow();
	row = new ReVarCifArray<CifString>;

	for (j=0; j < nCols; j++) {
	  row->Add(empty.Text());
	}
	
	for (j=0; j < nColsMap; j++) {
	  if (dMap[j]) {
	    if (_verbose)   _log << "Updating attribute cell " << indMap[j] << " value " 
				 <<  (*dMap[j])[k].Text() << endl;
	    (*row)[indMap[j]].Copy( (*dMap[j])[k].Text());
	  }
	}

	t->FillRow( *row, iRow);
	
	delete row;
      }
      fobjW->WriteTable(t,wBlockName,t->GetName());
    }

    for (j=0; j < nColsMap; j++) {
      if (dMap[j]) delete dMap[j];
    }
    if (dMap)      delete dMap;
    if (indMap)    delete indMap;
    if (cList)     delete cList;
    if (cNameMap)  delete cNameMap;
    if (iNameMap)  delete iNameMap;
    if (cIdMap)    delete cIdMap;
    if (fIdMap)    delete fIdMap;
    if (ir)        delete ir;
    if (irMap)     delete irMap;
    if (aI)        delete[] aI;
  }

  if (tList) delete tList;
}


ReVarCifArray<CifString> * CifSchemaMap::_DoFunc(ReVarCifArray<CifString> *r, const char *sFnct)
{
  ReVarCifArray<CifString> *s=NULL;
  CifString cs;
  char *p = NULL;
  int i,iOK;
  time_t curr_time;
  struct tm *tmptr = NULL;

  s = new ReVarCifArray<CifString>;

  if (!sFnct || !strlen(sFnct) || !strcmp(sFnct,"?") ) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      for (int i=0; i < (int) r->Length(); i++) {
	s->Add((*r)[i].Text());
      }
    }
  } else if (!strcmp(sFnct,"today()") ) {
#if 1
    p = new char[18];
    time(&curr_time);
    tmptr = localtime(&curr_time);
    strcpy(p,"");
    strftime(p,18,"%Y-%b-%d %R", tmptr);
    s->Add(p);
    if (p) delete(p);
#else
    cs.Clear(); cs.Copy("TEST");
    s->Add(cs.Text());
#endif

  } else if (!strcmp(sFnct,"prefix(PDB)") ) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      for (int i=0; i < (int) r->Length(); i++) {
        cs.Clear(); cs.Copy("PDB"); cs += (*r)[i].Text();
	s->Add(cs.Text());
      }
    }
  } else if (!strcmp(sFnct,"prefixUp(PDB)") ) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      for (int i=0; i < (int) r->Length(); i++) {
#if 0
	p = new char[(*r)[i].Length()+4];
	strcpy(p,"PDB");
	strcat(p,(*r)[i].Text());
	_ToUpperString(p);
	s->Add(p);
	if (p) delete p;

#else
        cs.Clear(); cs.Copy("PDB"); 
	cs += (*r)[i].Text();
	_ToUpperString(cs.Text());
	s->Add(cs.Text());
#endif
      }
    }

  } else if (!strcmp(sFnct,"datecnv(sybase)")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      char sybdate[20];
      for (int i=0; i < (int) r->Length(); i++) {
	_dformat_3((*r)[i].Text(),sybdate, 0);
	s->Add(sybdate);
      }
    }

  } else if (!strcmp(sFnct,"datecnv(sybase-short)")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      char sybdate[20];
      for (int i=0; i < (int) r->Length(); i++) {
	_dformat_3((*r)[i].Text(),sybdate, 1);
	s->Add(sybdate);
      }
    }

  } else if (!strcmp(sFnct,"datecnv(oracle-short)")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      char sybdate[20];
      for (int i=0; i < (int) r->Length(); i++) {
	_dformat_5((*r)[i].Text(),sybdate);
	s->Add(sybdate);
      }
    }

  } else if (!strcmp(sFnct,"row()")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      for (int i=1; i <= (int) r->Length(); i++) {
	cs.Clear();
	cs += (int) i;
	s->Add(cs.Text());
      }
    }

  } else if (!strcmp(sFnct,"toupper()")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      for (int i=0; i < (int) r->Length(); i++) {
#if 0
	p = new char[(*r)[i].Length()+1];
	strcpy(p,(*r)[i].Text());
	_ToUpperString(p);
	s->Add(p);
	if (p) delete p;
#else
	cs.Clear(); cs.Copy((*r)[i].Text());
	_ToUpperString(cs.Text());
	s->Add(cs.Text());
#endif
      }
    }

  } else if (!strcmp(sFnct,"strip(ws)") || !strcmp(sFnct,"strip()")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      for (int i=0; i < (int) r->Length(); i++) {
	cs.Clear(); cs.Copy((*r)[i].Text());
	_StripString(cs.Text(),1);
	s->Add(cs.Text());
      }
    }

  } else if (!strcmp(sFnct,"strip(nl)")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      for (int i=0; i < (int) r->Length(); i++) {
	cs.Clear(); cs.Copy((*r)[i].Text());
	_StripString(cs.Text(),2);
	s->Add(cs.Text());
      }
    }



  } else if (!strcmp(sFnct,"collapse(comma)")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
    } else {
#if 0
      cs.Clear();
      for (i=0; i < (int) r->Length(); i++) {
	cs += (*r)[i].Text();
	if (i < r->Length() - 1) cs += ", ";
      }
#else
      int ilen  = 0;
      for (i=0; i < (int) r->Length(); i++) {
	ilen += (*r)[i].Length() + 3; 
      }
      char *buf = (char *) calloc(ilen+1, sizeof(char));
      strcpy(buf,"");
      for (i=0; i < (int) r->Length(); i++) {
	strcat(buf, (*r)[i].Text());
	if (i < (int) r->Length()-1) strcat(buf,", ");
      }
      cs.Clear(); cs.Copy(buf);
      free(buf);
      
#endif

    }
    s->Add(cs.Text());

  } else if (!strcmp(sFnct,"collapse(comma,cnvname)")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
    } else {
#if 0
      cs.Clear();
      for (i=0; i < (int) r->Length(); i++) {
	cs += (*r)[i].Text();
	if (i < r->Length() - 1) cs += ", ";
      }
#else
      int ilen  = 0;
      for (i=0; i < (int) r->Length(); i++) {
	ilen += (*r)[i].Length() + 2; 
      }
      char *buf = (char *) calloc(ilen+1, sizeof(char));
      strcpy(buf,"");
      for (i=0; i < (int) r->Length(); i++) {
	_ReorderName((*r)[i].Text(),1);
	strcat(buf, (*r)[i].Text());
	if (i < (int) r->Length()-1) strcat(buf,", ");
      }
      cs.Clear(); cs.Copy(buf);
      free(buf);
      
#endif

    }
    s->Add(cs.Text());
  } else if (!strcmp(sFnct,"collapse(space)")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
    } else {
#if 0     
      cs.Clear();
      for (i=0; i < (int) r->Length(); i++) {
	cs += (*r)[i].Text();
	if (i < (int) r->Length() - 1) cs += " ";
      }
#else
      int ilen  = 0;
      for (i=0; i < (int) r->Length(); i++) {
	ilen += (*r)[i].Length() + 2; 
      }
      char *buf = (char *) calloc(ilen+1, sizeof(char));
      strcpy(buf,"");
      for (i=0; i < (int) r->Length(); i++) {
	strcat(buf, (*r)[i].Text());
	strcat(buf," ");
      }
      cs.Clear(); cs.Copy(buf);
      free(buf);      
#endif
    }
    s->Add(cs.Text());

  } else if (!strcmp(sFnct,"collapse()")) {
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
    } else {
#if 0
      cs.Clear();
      for (i=0; i < (int) r->Length(); i++) {
	cs += (*r)[i].Text();
      }
#else
      int ilen  = 0;
      for (i=0; i < (int) r->Length(); i++) {
	ilen += (*r)[i].Length(); 
      }
      char *buf = (char *) calloc(ilen+1, sizeof(char));
      strcpy(buf,"");
      for (i=0; i < (int) r->Length(); i++) {
	strcat(buf, (*r)[i].Text());
      }
      cs.Clear(); cs.Copy(buf);
      free(buf);      
#endif

    }
    s->Add(cs.Text());
  } else   if (!strcmp(sFnct,"count()")) {
    if (!r || !r->Length()) {
      s->Add("0");
    } else {
      cs.Clear();
      cs += (int) r->Length();
      s->Add(cs.Text());
    }
  } else   if (!strcmp(sFnct,"ifany()")) { // one or more non-null values ...
    if (!r || !r->Length()) {
      s->Add("N");
    } else {
      iOK=0;
      for (i=0; i < (int) r->Length(); i++) {
	if ( ((*r)[i].Length() > 0) && strcmp((*r)[i].Text(),"?") && strcmp((*r)[i].Text(),".")) iOK++;
      }
      if (iOK) 
	s->Add("Y");
      else
	s->Add("N");
    }

  } else   if (!strcmp(sFnct,"tobool()")) { // convert y/yes -> 1  anyother,NULL,missing -> 0
    if (!r || !r->Length()) {
      s->Add("0");
    } else {
      for (i=0; i < (int) r->Length(); i++) {
	if ( ((*r)[i].Length() > 0) && strcmp((*r)[i].Text(),"?") && strcmp((*r)[i].Text(),".")) {
	  if ( !strcasecmp((*r)[i].Text(),"Y") || !strcasecmp((*r)[i].Text(),"yes")) 
	    s->Add("1");
	  else
	    s->Add("0");
	} else {  //  NULLS map to 0
	  s->Add("0");
	}
      }
    }
      
  } else   if (!strncmp(sFnct,"ifexists(",9)) { // one or more non-null values ...
    if (!r || !r->Length()) {
      s->Add("N");
    } else {
      iOK=0;
      p = new char[strlen(sFnct) + 1];
      strcpy(p,&sFnct[9]);
      p[strlen(p)-1] = '\0';
      cs.Clear(); cs.Copy(p);

      for (i=0; i < (int) r->Length(); i++) {
	if ( ((*r)[i].Length() > 0) && strcmp((*r)[i].Text(),"?") && strcmp((*r)[i].Text(),".")) {
	  iOK++;
	  s->Add(cs.Text());
	} else {
	  s->Add("");	  
	}
      }
      if (p) delete p;
    }
  } else   if (!strcmp(sFnct,"first()")) { // first() of possibly multiple values
    if (!r || !r->Length()) {
      cs.Clear(); cs.Copy("");
      s->Add(cs.Text());
    } else {
      s->Add((*r)[0].Text());
    }
  } else {
    if (!r || !r->Length()) {
      cs.Clear();
      s->Add(cs.Text());
    } else {
      for (i=0; i < (int) r->Length(); i++) {
	s->Add((*r)[i].Text());
      }
    }
  }
  return(s);
}

#if 0

void CifSchemaMap::_AddIndex(ISTable *t, const char *columnName) 
{
  int iCol;
  ReVarCifArray<CifString> *tCol = NULL;

  iCol = t->GetColumnIndex(columnName);
  if (iCol < 0) {
    if (_verbose) _log << "*** Column "<< columnName << " missing in table " << t->GetName() << endl;
    return;
  }
  if (!t->isIndexed(iCol)) { // make this column searchable
      tCol = t->GetColumn(iCol);
      if (_verbose) _log << "Add index on column " << columnName << " number " << iCol 
			 << " length " << tCol->Length() << endl;
      t->RemoveColumn(iCol);
      t->InsertColumn(columnName,iCol,1);
      t->FillColumn(*tCol,iCol);
      if (tCol) delete tCol;
  }
}
#endif


int CifSchemaMap::_GetMapColumnIndex(ReVarCifArray<CifString> *cNameMap, const char *vOf) 
{
  char *p=NULL;
  CifString cs1;
  int j, jCol=-1;

  if ( !strncmp(vOf,"valueof(",8) || !strncmp(vOf,"unseqof(",8) ) {
    p = new char[strlen(vOf) + 1];
    strcpy(p,&vOf[8]);
    p[strlen(p)-1] = '\0';
    cs1.Clear(); cs1.Copy(p);
    if (p) delete p;
    if (_verbose) _log << "Map join attribute is " << cs1.Text() << endl;
    jCol = -1;
    for (j=0; j < (int) cNameMap->Length(); j++) {
      if (!CompareNoCase(cs1, (*cNameMap)[j])) {
	jCol = j; 
	break;
      }
    }
    if (jCol < 0) {
      if (_verbose) _log << "Attribute " << cs1.Text() << " is not in map" << endl;
    }
  }
  return(jCol);
}


char * CifSchemaMap::_GetMapColumnValue(ReVarCifArray<CifString> **dMap,  int iCol,  int irow)
{
  char * p = NULL; 
  int nRows = 0, len = 0;

  if (_verbose) _log << " ** Fetching values from map column " << iCol << " row " << irow << endl;

  if (iCol < 0 ) return(p); 
  if (irow < 0 || (irow >= (int) dMap[iCol]->Length())) return(p);
  nRows= dMap[iCol]->Length();  

  if (_verbose) _log << " ** Fetching value from map column " << iCol << " row " << irow 
		     << " of " << nRows << endl;

  len = (*dMap[iCol])[irow].Length();
  if (len > 0) {
    p  = new char [ len + 1];
    strcpy(p,(*dMap[iCol])[irow].Text());
  } 
  return(p);
}


int CifSchemaMap::_GetMapColumnLength(ReVarCifArray<CifString> **dMap,   int iCol)
{
  int len=0;
  if (iCol < 0 ) return(0);
  if (!dMap[iCol]) return(0);
  len = dMap[iCol]->Length(); 
  if (_verbose) {
    _log << " ** Length of map column " << iCol << " is " << len << endl; 
  }
  return(len);
}


int CifSchemaMap::_Search(CifFileObj *fobjR, const char *rBlockName,  // Source data
			  ReVarCifArray<CifString> *cNameMap,         // mapped attributes 
			  const char *sItem,                          // source item
			  const char *sCnd, const char *sFnct,        // condition and function code
			  ReVarCifArray<CifString> **dMap,            // container for output
			  int *indMap, int iAttrib) {                 // index between map and schema

  ReVarCifArray<CifString> *r    = NULL;
  ReVarPCifArray<int>      * ir  = NULL;
  ReVarPCifArray<int>      * is  = NULL;
  ReVarCifArray<CifString> *cndCol = NULL;
  ReVarCifArray<CifString> *cndVal = NULL;
  CifString csTarget, cs;
  int i, j, iCol, errCode=0, nEqCnd, maxLen, iFlagValueOf=0; 
  char tableName[_MAX_NAME_LENGTH], columnName[_MAX_NAME_LENGTH];
  
  int *indDMap = NULL;
  int *lenDMap = NULL;
  int lenMin = -1, lenMax = -1;
  ReVarCifArray<CifString> *tRes    = NULL;
  ReVarCifArray<CifString> *r1    = NULL;
  char *p = NULL;
  long long hashId;
  

  if (!fobjR) return(0);
  if (!rBlockName) return(0);
  //
  // jdw catch the special cases of a constant non-schema mapping
  //

  if (sFnct && !strcmp(sFnct,"today()")) {
    if (_verbose) _log << "Constant function today()" << endl;
    dMap[iAttrib] = _DoFunc(r, sFnct);
    if (_verbose) {
      _log << "Returning result length " << dMap[iAttrib]->Length() << endl;
      for (i=0; i < (int) dMap[iAttrib]->Length(); i++) {
	_log << "Returning value " << (*dMap[iAttrib])[i].Text() << endl;
      }
    }
    return(1);
  } else if (sFnct && !strcmp(sFnct,"datablockid()")) {
    if (_verbose) _log << "Constant function datablockid()" << endl;
    ReVarCifArray<CifString> *s= new ReVarCifArray<CifString>;
    s->Add(rBlockName);
    dMap[iAttrib] = s;

    if (_verbose) {
      _log << "Returning result length " << dMap[iAttrib]->Length() << endl;
      for (i=0; i < (int) dMap[iAttrib]->Length(); i++) {
	_log << "Returning value " << (*dMap[iAttrib])[i].Text() << endl;
      }
    }
    return(1);
  } else if (sFnct && !strcmp(sFnct,"unseq()")) { // unseq() unique sequence using pdb hash code

    hashId = pdbIdHash(_HASH_ID);

    if (_verbose) {
      _log << "Function seqid()" << endl;
      _log << "Block id "<< rBlockName << endl;
      _log << "Hash id "<< (long)hashId  << endl;
    }

    ReVarCifArray<CifString> *s= new ReVarCifArray<CifString>;
    maxLen = 0;
    for (i=0; i < iAttrib; i++) {
      if (!dMap[i]) continue;
      j=dMap[i]->Length();
      if (j > maxLen) maxLen = j;
    }
    if (maxLen>0) {
      for (i=1; i <= maxLen; i++) {
	csTarget.Clear();  csTarget += (long long) hashId +  (long long) i;
	if (_verbose) _log << "hashid csTarget " << csTarget.Text() << endl;
        s->Add(csTarget.Text());
      }
    } else {
      s->Add("");

    }
    dMap[iAttrib]=s;
    return(1);

  } else if (sFnct && !strcmp(sFnct,"row()")) {
    if (_verbose) _log << "Function row()" << endl;
    ReVarCifArray<CifString> *s= new ReVarCifArray<CifString>;
    maxLen = 0;
    for (i=0; i < iAttrib; i++) {
      if (!dMap[i]) continue;
      j=dMap[i]->Length();
      if (j > maxLen) maxLen = j;
    }
    if (maxLen>0) {
      for (i=1; i <= maxLen; i++) {
	csTarget.Clear();  csTarget += (int) i;
        s->Add(csTarget.Text());
      }
    } else {
      s->Add("");

    }
    dMap[iAttrib]=s;
    return(1);
  }

  if (! (sItem && _GetKeywordFromItemName(columnName,sItem) && 
	_GetCategoryNameFromItemName(tableName,sItem)))  return(0);


  if (_verbose) _log << "Searching block " << rBlockName << " table " 
		     << tableName << " column " << columnName << endl;

  ISTable *t = fobjR->GetTablePtr(rBlockName,tableName);
  if (!t) {
    if (_verbose) _log << "Target table " << tableName << " not in " << rBlockName << endl; 
    return(0);
  }

  iCol = t->GetColumnIndex(columnName);
  if (iCol < 0 ) { 
    if (_verbose) _log << "Target columnName " << columnName << " not in " << tableName << endl; 
    return(0);
  }


  if (sCnd && (strlen(sCnd) > 0)) { // fetch condition 

    if (_verbose) _log << "Using search condition " << sCnd << endl;

    csTarget.Clear(); csTarget.Copy(sCnd);

    ir = _mapConditions->SearchColumn(csTarget, _cInMCConditionId, errCode);


    if ( ir && ir->Length() > 0) {  // list of constraints for condition.

      cndCol = _mapConditions->GetSubColumnByIndex(_cInMCAttributeName,ir);
      cndVal = _mapConditions->GetSubColumnByIndex(_cInMCAttributeValue,ir);
      nEqCnd=0;
      for (i=0; i < (int) ir->Length(); i++) {
	//	_AddIndex(t,(*cndCol)[i].Text()); // make column searchable

	if ( !strcmp( (*cndVal)[i].Text(),"datablockid()")) {
	  (*cndVal)[i].Clear(); (*cndVal)[i].Copy(rBlockName);
	}

	if ( !strncmp( (*cndVal)[i].Text(),"valueof(",8) || !strncmp( (*cndVal)[i].Text(),"unseqof(",8) ) {
	  nEqCnd++;
	}

	if (_verbose) _log << "Condition column " << (*cndCol)[i].Text() << " value " 
			   << (*cndVal)[i].Text() << endl;
      }

      if (nEqCnd) {  // # of join conditions.


	indDMap = new int[ir->Length()];
	lenDMap = new int[ir->Length()];
	lenMin = -1; lenMax = -1;
	for (i=0; i < (int) ir->Length(); i++) {
	  indDMap[i] = -1;
	  lenDMap[i] =  0;
	  if ( !strcmp( (*cndVal)[i].Text(),"datablockid()")) {
	    (*cndVal)[i].Clear(); (*cndVal)[i].Copy(rBlockName);
	  }
	  if ( !strncmp( (*cndVal)[i].Text(),"valueof(",8) ||  !strncmp( (*cndVal)[i].Text(),"unseqof(",8)) {
	    indDMap[i] = _GetMapColumnIndex(cNameMap, (*cndVal)[i].Text());
	    lenDMap[i] = _GetMapColumnLength(dMap,indDMap[i]);
	    if (lenMin < 0 || lenDMap[i] < lenMin) lenMin  = lenDMap[i];
	    if (lenDMap[i] > lenMax)               lenMax  = lenDMap[i];
	    if (_verbose) _log << " ** value or unseqof() index " << indDMap[i] 
			       << " length " << lenDMap[i] << endl;
	  }
	}
	if (lenMin != lenMax) {
	  if (_verbose) _log << " ** valueof() or unseqof() column length inconsistency  lenMin " 
			     <<  lenMin << " lenMax " << lenMax << endl;
	}
	if (_verbose) _log << " ** valueof() or unseqof() column lenMin " <<  lenMin 
			   << " lenMax " << lenMax << endl;

	if (cndCol) delete (cndCol);cndCol=NULL;
	if (cndVal) delete (cndVal);cndVal=NULL;
	tRes = new ReVarCifArray<CifString>;
	for (j=0; j < lenMin; j++) {
	  cndCol = _mapConditions->GetSubColumnByIndex(_cInMCAttributeName, ir);
	  cndVal = _mapConditions->GetSubColumnByIndex(_cInMCAttributeValue, ir);
          if (_verbose) _log << " ** Starting row "<< j << " condition length " << ir->Length() << endl;

	  for (i=0; i < (int) ir->Length(); i++) {
	    if (_verbose) _log << " ** condition value " << i << " is " << (*cndVal)[i].Text() << endl;
	    
	    if ( !strcmp( (*cndVal)[i].Text(),"datablockid()")) {
	      (*cndVal)[i].Clear(); (*cndVal)[i].Copy(rBlockName);
	    }
	    
	    if ( !strncmp( (*cndVal)[i].Text(),"valueof(",8) || !strncmp( (*cndVal)[i].Text(),"unseqof(",8) ) {
              iFlagValueOf=1; 
	      if (!strncmp( (*cndVal)[i].Text(),"unseqof(",8)) iFlagValueOf=2; 
	      p = _GetMapColumnValue(dMap, indDMap[i], j);
	      if (!p) {
		(*cndVal)[i].Clear(); 
		(*cndVal)[i].Copy("NULL");
		if (_verbose) _log << " ** Map row " <<  j << " has value NULL" << endl;
	      } else {
		(*cndVal)[i].Clear(); 
		(*cndVal)[i].Copy(p);
		if (_verbose) _log << " ** Map row " <<  j << " has value " << p << endl;
		delete p;
	      }
	    } 
	    if (_verbose) _log << " ** Search column " <<  (*cndCol)[i].Text() << " for " 
			       << (*cndVal)[i].Text() << endl;
	  }


	  is = t->Search(*cndVal, *cndCol ,errCode);
	  if (_verbose) _log << " ** Error code is " <<  errCode << endl;

	  if ( is && is->Length() > 0) {
	    if (iFlagValueOf == 1 ) { // valueof()
	      if (_verbose) _log << " ** Search result length is " <<  is->Length() << " rows"<< endl;
	      r = t->GetSubColumnByIndex(iCol,is);
	    } else if (iFlagValueOf == 2) { // unseqof()
	      if (_verbose) _log << " ** Search result length is " <<  is->Length() << " rows"<< endl;
	      r = new ReVarCifArray<CifString>;
	      hashId = pdbIdHash(_HASH_ID);
	      for (int jj = 0; jj < (int) is->Length(); jj++) {
		cs.Clear(); cs += (long long) ((*is)[jj] + 1 + hashId);
		r->Add(cs.Text());
	      }
	    }

	  } else {
	    if (_verbose) {
	      _log << " ** ** ** ** ** Warning " << endl;
	      if (is == NULL) _log << " ** Search returns NULL" << endl;
	      if (is && is->Length() == 0 ) _log << " ** Search returns 0 length" << endl;
	    }
	    r = NULL;
	  }


	  r1 = _DoFunc(r, sFnct);
	  tRes->Add((*r1)[0].Text());
	  if (r1) delete r1;

	  //	  if (cndVal && cndVal->Length() ) delete cndVal;
	  //	  if (cndCol && cndCol->Length() ) delete cndCol;
	  if (cndVal ) delete cndVal; cndVal = NULL;
	  if (cndCol ) delete cndCol;cndCol = NULL;
	  if (is && is->Length() ) delete is;is = NULL;
	  if (r && r->Length()) delete r;r = NULL;

	} // end j loop	

	dMap[iAttrib] = _DoFunc(tRes,"?");  // copy expand the resulting column
	if (tRes) delete tRes;
	if (indDMap) delete indDMap;
	if (lenDMap) delete lenDMap;

      } else {  // if no join conditions nEqCnd ...

	is = t->Search(*cndVal, *cndCol ,errCode);
	if (_verbose) _log << "Error code is " <<  errCode << endl;
	if ( is && is->Length() > 0) {
	  r = t->GetSubColumnByIndex(iCol,is);
	}
	dMap[iAttrib] = _DoFunc(r, sFnct);
      }

      //      if (cndVal && cndVal->Length() ) delete cndVal;
      //      if (cndCol && cndCol->Length() ) delete cndCol;
      if (cndVal) delete cndVal;
      if (cndCol) delete cndCol;
      if (is && is->Length() ) delete is;
      if (ir && ir->Length() ) delete ir;
    } else {  // search condition missing in category
      r = t->GetColumn(iCol);
      dMap[iAttrib] = _DoFunc(r, sFnct);
    }
  } else { // no condition ...
    if (_verbose) _log << "No search condition specified, selecting column " << iCol << endl;
    r = t->GetColumn(iCol);
    if (_verbose && r == NULL) {
      _log << "Column "<< iCol << " returns NULL result." << endl;

    } else if (_verbose && r != NULL ) {
      _log << "Column "<< iCol << " returns length " << r->Length() << endl;
    }

    dMap[iAttrib] = _DoFunc(r, sFnct);

  }


  if (_verbose) {
    if (dMap[iAttrib]) {
      _log << "Returning result length " << dMap[iAttrib]->Length() << endl;
      for (i=0; i < (int) dMap[iAttrib]->Length(); i++) {
	_log << "Returning " << columnName << " value " << (*dMap[iAttrib])[i].Text() << endl;
      }
    } else {
      _log << "Returning result length 0 " << endl;
    }
  }
  delete r; //**********
  return (1);
}



void CifSchemaMap::_CreateTables(CifFileObj *fobj, const char *blockName) {
  // Create tables in the target schema ...
  int i, j, errCode;
  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> *cNames = NULL;
  ISTable *t = NULL;

  ReVarCifArray<CifString> *tNames =  _tableSchema->GetColumn(_cInTSTableName);


  for (i=0; i < (int) tNames->Length(); i++) {
    ir = _attribSchema->SearchColumn((*tNames)[i], _cInASTableName, errCode);
    if ( !ir || ir->Length() <= 0) continue;
    cNames = _attribSchema->GetSubColumnByIndex(_cInASAttributeName,ir);

    if (cNames->Length() != ir->Length()) 
      if (_verbose) _log << "Length of column name list inconsistent " 
	   <<  " cNames = "<< cNames->Length() 
	   <<  " ir = " << ir->Length() << endl; 

    t = new ISTable((*tNames)[i].Text());
    for (j=0; j < (int) cNames->Length(); j++) {
      t->AddColumn((*cNames)[j].Text(),FALSE);
      //      if (_verbose) _log << "Adding table " << (*tNames)[i].Text() 
      //			 <<  " column " <<  (*cNames)[j].Text() << endl;
    }
    fobj->WriteTable(t,blockName, t->GetName());

    if (ir) delete ir;
    if (cNames) delete cNames;

//    if (t) delete t;
  }
    if (tNames) delete tNames;

}


void CifSchemaMap::WriteSchemaSQL(int updateMode)
{
  int i;
  //
  // File for SQL output ...
  //
  _WriteScriptSchema();

  char *oFile = new char[strlen(_path) + strlen(_SCHEMA_SQL_FILE) + 1];
  strcpy(oFile,_path);
  strcat(oFile,_SCHEMA_SQL_FILE);
  ofstream io(oFile,ios::out|ios::trunc);

  if (_serverType == _SERVER_TYPE_ORACLE) {
    io << "set define off" << _cmdTerm << endl;
    io << "set escape \\" << _cmdTerm << endl;
  } else if (_serverType == _SERVER_TYPE_DB2) {
    io << endl;
  } else {
    io << "use " << _dbName << _cmdTerm << endl;
  }

  //
  // Generate SQL to create table schema...
  //

  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);
  for (i=0; i < (int) tableNames->Length(); i++) {
    _CreateTableSQL(io, (*tableNames)[i]);
  }

  //
  // Create tableinfo and columninfo tables which contain data about the schema.
  //
  ISTable *tinfo = _CreateTableInfo(_fobjS);

  if (updateMode) {
    _UpdateTableSQL(io, tinfo);
  } else {
    for (i=0; i < (int) tableNames->Length(); i++) {
      io << "delete from tableinfo  where tablename = '"  <<  (*tableNames)[i].Text() << "'" << _cmdTerm << endl;
    }
    _InsertTableSQL(io, tinfo);
  }

  ISTable *cinfo = _CreateColumnInfo(_fobjS);
  if (updateMode) {
    _UpdateTableSQL(io, cinfo);
  } else {
    for (i=0; i < (int) tableNames->Length(); i++) {
      io << "delete from columninfo  where tablename = '" << (*tableNames)[i].Text() << "'" << _cmdTerm << endl;
    }
    _InsertTableSQL(io, cinfo);
  }
  io.close();
  if (oFile) delete oFile;
  return;
}




void CifSchemaMap::_CreateTableSQL(ostream &io, CifString tableName)
{
  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  ReVarCifArray<CifString> * indexList = new ReVarCifArray<CifString>;
  int i, j, errCode, iLen;
  CifString columnName, dType, tableNameDb, columnNameDb;
  int iIndex, iNull, iWidth;
  char indName[40];
  //  int iPrecision;

  if (tableName.Length() <= 0) return;
  if (!io )   return;

  _GetTableNameAbbrev(tableNameDb, tableName);
  io << endl;
  io << endl;
  if (_serverType == _SERVER_TYPE_SYBASE)  
    io << "print \"Creating table " << tableNameDb.Text() << "\"" << endl;


  io << "drop table " << tableNameDb.Text() << _cmdTerm << endl;

  ir = _attribSchema->SearchColumn(tableName, _cInASTableName, errCode);
  if ( !ir || ir->Length() <= 0) return;

  io << "create table " << tableNameDb.Text() << endl;
  io << "(" << endl;
  for (i=0; i < (int) ir->Length(); i++) {
    row = _attribSchema->GetRow((*ir)[i]);
    if (row) {
      columnName.Clear(); columnName.Copy((*row)[_cInASAttributeName]);
      _GetAttributeNameAbbrev(columnNameDb,tableName,columnName);
      dType.Clear(); dType.Copy((*row)[_cInASDataType]);
      iIndex     = atoi((*row)[_cInASIndexFlag].Text());
      iNull      = atoi((*row)[_cInASNullFlag].Text());
      iWidth     = atoi((*row)[_cInASWidth].Text());
      //      iPrecision = atoi((*row)[_cInASPrecision].Text());
      //JDW
      //     io << columnName.Text();
      iLen = columnNameDb.Length(); if (iLen > 30) iLen = 30;
      for ( j=0; j < iLen; j++) {io << columnNameDb.Text()[j];};
      for ( j=iLen; j < 31; j++) {io << " "; };

      if (!strcasecmp(dType.Text(),"char")) {
	dType.Clear();
	dType.Copy("varchar(");
	dType += iWidth;
	dType += ")";
      } 
      if (_serverType == _SERVER_TYPE_ORACLE && !strcasecmp(dType.Text(),"text")) {
	if (iWidth > 4000) {
	  dType.Clear(); 	dType.Copy("varchar(4000)");
	} else {
	  dType.Clear(); 	dType.Copy("clob");
	}
      } 


      if (_serverType == _SERVER_TYPE_ORACLE && !strcasecmp(dType.Text(),"datetime")) {
	dType.Clear(); 	dType.Copy("date");
      }

      if (_serverType == _SERVER_TYPE_DB2 && !strcasecmp(dType.Text(),"text")) {
	if (iWidth == 0 ) {
	  dType.Clear(); 	
	  dType.Copy("varchar(4000)");
	} else if (iWidth < 32000 ) {
	  dType.Clear();
	  dType.Copy("varchar(");
	  dType += iWidth;
	  dType += ")";
	} else {
	  dType.Clear();
	  dType.Copy("clob(");
	  dType += iWidth;
	  dType += ")";
	}
      } 

      if (_serverType == _SERVER_TYPE_DB2  && !strcasecmp(dType.Text(),"datetime")) {
	dType.Clear(); 	dType.Copy("date");
      }

      if (_serverType == _SERVER_TYPE_DB2 && !strcasecmp(dType.Text(),"float")) {
	dType.Clear(); 	dType.Copy("decimal(14,4)");
      }

      io << dType.Text();
      for (j=dType.Length(); j < 15; j++) {io << " "; };

      if (iNull) {
	io << "not null";
      } else {
	if (_serverType == _SERVER_TYPE_DB2)
	  io << "        ";
	else
	  io << "    null";
      }

      if (i < (int) ir->Length() - 1  || _serverType == _SERVER_TYPE_ORACLE 
	  || _serverType == _SERVER_TYPE_DB2 )
	io << "," << endl;
      else
	io << endl;

      if (iIndex) indexList->Add(columnNameDb);
      delete(row);
    }
  }
  delete(ir);

  if (_serverType == _SERVER_TYPE_ORACLE || _serverType == _SERVER_TYPE_DB2) {
    io << "PRIMARY KEY (";
    for (i=0; i < (int) indexList->Length(); i++) {
      io << (*indexList)[i].Text();
      if (i < (int) indexList->Length() - 1) 
	io << ",";
      else
	io << " ";
    }
    io << ")" << endl;

  }
  if (_serverType == _SERVER_TYPE_DB2) {
     if (!strcmp(tableNameDb.Text(),"tableinfo")) {
       io << ") ";
       io << "partitioning key ( tablename ";
     } else if (!strcmp(tableNameDb.Text(),"columninfo")) {
       io << ") ";
       io << "partitioning key ( columnname ";
     } else {
       io << ") ";
       io << "partitioning key ( Structure_ID ";
       //    io << "partitioning key (";
       //    for (i=0; i < indexList->Length(); i++) {
       //      io << (*indexList)[i].Text();
       //      if (i < indexList->Length() - 1)        io << "," ;
       //    }
     }
    io <<") using hashing"<< _cmdTerm << endl;
  } else {
    io << ")"  << _cmdTerm << endl;
  }




  if (indexList && indexList->Length()) {

    if (_serverType == _SERVER_TYPE_SYBASE) {
      io << "create clustered index primary_index on " << tableNameDb.Text() << endl;
      io << "(" << endl;
      for (i=0; i < (int) indexList->Length(); i++) {
	io << (*indexList)[i].Text();
	if (i < (int) indexList->Length() - 1) 
	  io << "," << endl;
	else
	  io << endl;
      }
      io << ")" ;

    }  else if (_serverType == _SERVER_TYPE_MYSQL) {
      io << "create unique index primary_index on " << tableNameDb.Text() << endl;
      io << "(" << endl;
      for (i=0; i < (int) indexList->Length(); i++) {
	io << (*indexList)[i].Text();
	if (i < (int) indexList->Length() - 1) 
	  io << "," << endl;
	else
	  io << endl;
      }
      io << ")" ;

    } else if (_serverType == _SERVER_TYPE_DB2) {
      strcpy(indName,"I");
      strncat(indName,tableNameDb.Text(),28);
      //      io << "create unique index " << indName << " on " << tableName.Text() << endl;
      //io << "(" << endl;
      //for (i=0; i < indexList->Length(); i++) {
      //	io << (*indexList)[i].Text();
      //	if (i < indexList->Length() - 1) 
      //	  io << "," << endl;
      //	else
      //	  io << endl;
      //      }
      //      io << ")" ;

    } else if (_serverType == _SERVER_TYPE_ORACLE) {
      strcpy(indName,"I");
      strncat(indName,tableNameDb.Text(),28);
      //      io << "create unique index " << indName << " on " << tableName.Text() << endl;
      //      io << "(" << endl;
      //      for (i=0; i < indexList->Length(); i++) {
      //	io << (*indexList)[i].Text();
      //	if (i < indexList->Length() - 1) 
      //	  io << "," << endl;
      //	else
      //	  io << endl;
      //      }
      //      io << ")" ;

    }
    

    if (_serverType == _SERVER_TYPE_SYBASE) 
      io << " with ignore_dup_row" << _cmdTerm << endl;
    else if (_serverType != _SERVER_TYPE_ORACLE) {
      io << _cmdTerm << endl;
    }
    delete indexList;
  }
  
  io << "grant select on " << tableNameDb.Text() << " to " << _dbUser << _cmdTerm << endl;
  io << "grant insert, delete, update, select on " << tableNameDb.Text(); 

  if (_serverType == _SERVER_TYPE_SYBASE) 
    io << " to dbo" << _cmdTerm << endl;
  else   if (_serverType == _SERVER_TYPE_MYSQL) 
    io << " to " << _dbMgr << _cmdTerm << endl;
  else   if (_serverType == _SERVER_TYPE_DB2) 
    io << " to " << _dbMgr << _cmdTerm << endl;
  else   if (_serverType == _SERVER_TYPE_ORACLE) 
    io << " to " << _dbMgr << _cmdTerm << endl;

}


void CifSchemaMap::WriteSchemaXML()
{
  int i;
  CifString  tableNameDb;
  //
  // File for XML XSD output ...
  //
  char *oFile = new char[strlen(_path) + strlen(_SCHEMA_XML_FILE) + 1];
  strcpy(oFile,_path);
  strcat(oFile,_SCHEMA_XML_FILE);
  ofstream io(oFile,ios::out|ios::trunc);

  io << "<?xml version=\"1.0\"?>" << endl;
#if 0
  io << "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << endl
     << "            xmlns:mmcif=\"http://deposit.pdb.org/mmcif/mmcif\"" << endl
     << "            xmlns:pdbx=\"http://deposit.pdb.org/mmcif/pdbx\"" << endl
     << "            xmlns:ndb=\"http://deposit.pdb.org/mmcif/ndb\">" << endl;
#else
  io << "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >" << endl;
    //     << "            targetNamespace = \"http://deposit.pdb.org/mmcif/pdbx\"" << endl
    //     << "            xmlns = \"http://deposit.pdb.org/mmcif/pdbx\" >" << endl;
#endif
  //
  //
  // Generate XML complex types...
  //

  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);
  for (i=0; i < (int) tableNames->Length(); i++) {
    _CreateComplexTypeXML(io, (*tableNames)[i]);
  }
  
  io << "      <xsd:complexType name=\"datablockType\">" << endl;
  io << "        <xsd:all>" << endl;
  for (i=0; i < (int) tableNames->Length(); i++) {
    _GetTableNameAbbrevXML(tableNameDb, (*tableNames)[i]);
    if (!strncmp("pdbx_",tableNameDb.Text(),5)) {
      io <<  "          <xsd:element ref=\"category_" << tableNameDb.Text()  << "\"" 
	 << " minOccurs=\"0\" maxOccurs=\"1\" />" << endl;
    } else if (!strncmp("ndb_",tableNameDb.Text(),4)) {
      io <<  "          <xsd:element ref=\"category_" << tableNameDb.Text()  << "\"" 
	 <<  " minOccurs=\"0\" maxOccurs=\"1\" />" << endl;
    } else {
      io <<  "          <xsd:element ref=\"category_" << tableNameDb.Text() << "\"" 
	 <<  " minOccurs=\"0\" maxOccurs=\"1\" />" << endl;
    }
  }
  io << "        </xsd:all>" << endl;  
  io << "        <xsd:attribute name=\"datablockName\" " ;
  io << "type=\"xsd:string\" " ;
  io << "use=\"optional\" ";
  io << " />" << endl;
  io << "      </xsd:complexType>" << endl;


  for (i=0; i < (int) tableNames->Length(); i++) {
    _GetTableNameAbbrevXML(tableNameDb, (*tableNames)[i]);
#if 0
    if (!strncmp("pdbx_",tableNameDb.Text(),5)) {
      io <<  "          <xsd:element name=\"pdbx:category_" << tableNameDb.Text()  << "\"" 
	 << "  type=\"" << tableNameDb.Text()  << "Type\" />" << endl;
    } else if (!strncmp("ndb_",tableNameDb.Text(),4)) {
      io <<  "          <xsd:element name=\"ndb:category_" << tableNameDb.Text()  << "\"" 
	 <<  "  type=\"" << tableNameDb.Text() << "Type\" />" << endl;
    } else {
      io <<  "          <xsd:element name=\"mmcif:category_" << tableNameDb.Text() << "\"" 
	 <<  "  type=\"" << tableNameDb.Text()  << "Type\" />" << endl;
    }
#else
    if (!strncmp("pdbx_",tableNameDb.Text(),5)) {
      io <<  "      <xsd:element name=\"category_" << tableNameDb.Text()  << "\"" 
	 << "  type=\"" << tableNameDb.Text()  << "Type\" />" << endl;
    } else if (!strncmp("ndb_",tableNameDb.Text(),4)) {
      io <<  "      <xsd:element name=\"category_" << tableNameDb.Text()  << "\"" 
	 <<  "  type=\"" << tableNameDb.Text() << "Type\" />" << endl;
    } else {
      io <<  "      <xsd:element name=\"category_" << tableNameDb.Text() << "\"" 
	 <<  "  type=\"" << tableNameDb.Text()  << "Type\" />" << endl;
    }

#endif

  }

#if 0
  io << "        <xsd:element name=\"datablock\" " 
     << "  type=\"datablockType\"  minOccurs=\"0\" maxOccurs=\"unbounded\" />" << endl;
#else
  io << "      <xsd:element name=\"datablock\" " 
     << "  type=\"datablockType\" />" << endl;
#endif
  io << "</xsd:schema>" << endl;

  io.close();
  if (oFile) delete oFile;
  return;
}


void CifSchemaMap::_CreateComplexTypeXML(ostream &io, CifString tableName)
{
  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  //  ReVarCifArray<CifString> * indexList = new ReVarCifArray<CifString>;
  int i, errCode;
  CifString columnName, dType, tableNameDb, columnNameDb;
  int iIndex /*, iNull, iWidth */ ;
  // char indName[40];
  //  int iPrecision;

  if (tableName.Length() <= 0) return;
  if (!io )   return;
  _GetTableNameAbbrevXML(tableNameDb, tableName);

  io << endl;
#if 0
  if (!strncmp("pdbx_",tableNameDb.Text(),5)) {
    io <<  "      <xsd:complexType name=\"pdbx:" << tableNameDb.Text()  << "Type\">" << endl;
    _SetNamespaceDefaultXML("pdbx"); 
  } else if (!strncmp("ndb_",tableNameDb.Text(),4)) {
    io <<  "      <xsd:complexType name=\"ndb:" << tableNameDb.Text()  << "Type\">" << endl;
    _SetNamespaceDefaultXML("ndb"); 
  } else {
    io <<  "      <xsd:complexType name=\"mmcif:" << tableNameDb.Text()  << "Type\">" << endl;
    _SetNamespaceDefaultXML("mmcif"); 
  }
#else
  if (!strncmp("pdbx_",tableNameDb.Text(),5)) {
    io <<  "      <xsd:complexType name=\"" << tableNameDb.Text()  << "Type\">" << endl;
    _SetNamespaceDefaultXML("pdbx"); 
  } else if (!strncmp("ndb_",tableNameDb.Text(),4)) {
    io <<  "      <xsd:complexType name=\"" << tableNameDb.Text()  << "Type\">" << endl;
    _SetNamespaceDefaultXML("ndb"); 
  } else {
    io <<  "      <xsd:complexType name=\"" << tableNameDb.Text()  << "Type\">" << endl;
    _SetNamespaceDefaultXML("mmcif"); 
  }

#endif
  //  Add new stuff 
  io << "        <xsd:sequence>" << endl;
  io << "        <xsd:element name=\"" << tableNameDb.Text() << "\"" 
     <<  " minOccurs=\"0\" maxOccurs=\"unbounded\" >" <<   endl;
  io << "        <xsd:complexType>" << endl;



  // Get attribute level information
  //
  ir = _attribSchema->SearchColumn(tableName, _cInASTableName, errCode);
  if ( !ir || ir->Length() <= 0) return;

  io << "        <xsd:sequence>" << endl;

  for (i=0; i < (int) ir->Length(); i++) {
    row = _attribSchema->GetRow((*ir)[i]);
    if (row) {
      columnName.Clear(); columnName.Copy((*row)[_cInASAttributeName]);
      _GetAttributeNameAbbrevXML(columnNameDb,tableName,columnName);
      dType.Clear(); dType.Copy((*row)[_cInASDataType]);
      iIndex     = atoi((*row)[_cInASIndexFlag].Text());
      // iNull      = atoi((*row)[_cInASNullFlag].Text());
      // iWidth     = atoi((*row)[_cInASWidth].Text());
      //      iPrecision = atoi((*row)[_cInASPrecision].Text());
      if (iIndex || !strcasecmp(columnName.Text(),"structure_id")) { // index items are displayed as attributes.
	delete(row);
	continue;
      }

      io << "            <xsd:element name=\"" ;
      _QualifyNameXML(io,columnNameDb.Text()); 
      io << "\" ";
      io << "type=\"" ;
      _ConvertDataTypeXML(io,dType);
      io << "\" ";
      io << " minOccurs=\"0\" maxOccurs=\"1\" nillable=\"true\" ";
      io << " />" << endl;

      delete(row);
    }
  }
  //
  io <<  "        </xsd:sequence>"   << endl;

  //  indices as attributes

  for (i=0; i < (int) ir->Length(); i++) {
    row = _attribSchema->GetRow((*ir)[i]);
    if (row) {
      columnName.Clear(); columnName.Copy((*row)[_cInASAttributeName]);
      _GetAttributeNameAbbrev(columnNameDb,tableName,columnName);
      dType.Clear(); dType.Copy((*row)[_cInASDataType]);
      iIndex     = atoi((*row)[_cInASIndexFlag].Text());
      // iNull      = atoi((*row)[_cInASNullFlag].Text());
      // iWidth     = atoi((*row)[_cInASWidth].Text());
      //      iPrecision = atoi((*row)[_cInASPrecision].Text());

      if (!iIndex || !strcasecmp(columnName.Text(),"structure_id")) {
	delete(row);
	continue;
      }

      io << "        <xsd:attribute name=\"" ;
      _QualifyNameXML(io,columnNameDb.Text());
      io << "\" ";
      io << "type=\"" ;
      _ConvertDataTypeXML(io,dType);
      io << "\" ";
      io << "use=\"required\"";
      io << " />" << endl;

      delete(row);
    }
  }
  io <<  "      </xsd:complexType>" << endl;
  io <<  "      </xsd:element>" << endl;
  io <<  "      </xsd:sequence>" << endl;

  io <<  "      </xsd:complexType>" << endl << endl;
  delete(ir);
  //  END of TYPE DEFINITION

}


static void _ConvertDataTypeXML(ostream &io,  CifString dType)
{

  if (!strcasecmp(dType.Text(),"char") ||!strcasecmp(dType.Text(),"text") ) {
    dType.Clear();
    dType.Copy("xsd:string");
  } 

  if (!strcasecmp(dType.Text(),"float") ||!strcasecmp(dType.Text(),"double") ) {
    dType.Clear();
    dType.Copy("xsd:decimal");
  } 

  if (!strcasecmp(dType.Text(),"int") || !strcasecmp(dType.Text(),"integer") || !strcasecmp(dType.Text(),"bigint") ) {
    dType.Clear();
    dType.Copy("xsd:integer");
  } 

  if (!strcasecmp(dType.Text(),"date") ||!strcasecmp(dType.Text(),"datetime") ) {
    dType.Clear();
    dType.Copy("xsd:date");
  } 

  io << dType.Text();

}




void CifSchemaMap::_QualifyNameWithNSXML(ostream &io,  const char *name) 
{
  int i;


  if (!strncmp("pdbx_",name,5)) {
    io << "pdbx:";
  } else if (!strncmp("ndb_",name,4)) {
    io << "ndb:" ;

  } else {
    _GetDefaultNamespaceXML(io);
  }


  for (i=0; i < (int) strlen(name); i++) {
    if (name[i] == '[' || name[i] == ']' || name[i] == '%' || name[i] == '<' || name[i] == '>') 
      continue;
    else 
      io << name[i];
  }
}

void CifSchemaMap::_QualifyNameXML(ostream &io,  const char *name) 
{
  int i;

#if 0
  if (!strncmp("pdbx_",name,5)) {
    io << "pdbx:";
  } else if (!strncmp("ndb_",name,4)) {
    io << "ndb:" ;

  } else {
    _GetDefaultNamespaceXML(io);
  }
#endif

  for (i=0; i < (int) strlen(name); i++) {
    if (name[i] == '[' || name[i] == ']' || name[i] == '%' || name[i] == '<' || name[i] == '>') 
      continue;
    else 
      io << name[i];
  }
}




ATTRIBINFO *CifSchemaMap::_GetAllAttributeInfo(CifString tableName) 
{
  // Return array of ATTRIBINFO for the name input table  .
  ATTRIBINFO *aI = NULL;

  //  const char *tableNameC  = NULL;
  int  nattrib;
  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  int i, j, nCols, errCode;
  CifString columnName;

  ir = _attribSchema->SearchColumn(tableName, _cInASTableName, errCode);

  if ( !ir || ir->Length() <= 0) {
    if (_verbose) _log << "_GetAllAttributeInfo: No attributes for found for " << tableName.Text() << endl;
    return(aI);
  }


  nCols = ir->Length();
  if (_verbose) _log << "_GetAllAttributeInfo: +++ TABLE " << tableName.Text() 
		     << " columns " << nCols << endl;
  if (!nCols)  return(aI);

  aI = new ATTRIBINFO [nCols+1];
  for (j=0; j < nCols; j++) {
    aI[j].dType.Clear(); 
    aI[j].iIndex     = -1;
    aI[j].iNull      = -1;
    aI[j].iWidth     = -1;
    aI[j].iPrecision = -1;
    aI[j].iTypeCode  = -1;
    aI[j].iMaxWidth  = -1;
  }

  //
  // Get all of the attributes for this table.
  //

  nattrib=0;
  for (i=0; i < (int) ir->Length(); i++) {
    row = _attribSchema->GetRow((*ir)[i]);
    if (row) {
      columnName.Clear(); columnName.Copy((*row)[_cInASAttributeName]);
      j = i;
      if (_verbose) _log << "_GetAllAttributeInfo: Column [" << j << "] " <<  columnName.Text() << endl;
      if (j >= 0  && j < nCols) {
	aI[j].dType.Clear(); aI[j].dType.Copy((*row)[_cInASDataType]);
	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"char")) {
	  aI[j].iTypeCode = _TYPE_CODE_STRING;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"int")) {
	  aI[j].iTypeCode = _TYPE_CODE_INT;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"float")) {
	  aI[j].iTypeCode = _TYPE_CODE_FLOAT;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"text")) {
	  aI[j].iTypeCode = _TYPE_CODE_TEXT;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"datetime")) {
	  aI[j].iTypeCode = _TYPE_CODE_DATETIME;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"bigint")) {
	  aI[j].iTypeCode = _TYPE_CODE_BIGINT;
	}
	
	aI[j].iIndex     = atoi((*row)[_cInASIndexFlag].Text());
	aI[j].iNull      = atoi((*row)[_cInASNullFlag].Text());
	aI[j].iWidth     = atoi((*row)[_cInASWidth].Text());
	aI[j].iPrecision = atoi((*row)[_cInASPrecision].Text());


	if (_verbose) _log << " Width " << aI[j].iWidth << " Type  " << aI[j].iTypeCode 
                           << " Index " << aI[j].iIndex << " Null " << aI[j].iNull << endl;
        nattrib++;
      } 
      delete row;
    }

  }
  if (nattrib < nCols) {
    if (_verbose) _log << "GetAllAttributeInfo(): warning unmapped column nattrib = " << nattrib  << endl;
  }
  if (_verbose) _log << "_GetAllAttributeInfo: +++ DONE WITH " << tableName.Text() << endl << endl;

  delete(ir);
  return(aI);
}


ATTRIBINFO *CifSchemaMap::_GetAttributeInfo(ISTable *tIn)
{
  // Return array of ATTRIBINFO for the input table.
  ATTRIBINFO *aI = NULL;

  const char *tableNameC  = NULL;
  int  nattrib;
  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  int i, j, nCols, errCode;
  CifString columnName, tableName;

  if (!tIn ) return(aI);

  tableNameC = tIn->GetName();
  if (tableNameC == NULL || !strlen(tableNameC)) return(aI);

  nCols = tIn->GetNumColumns();
  if (!nCols)  return(aI);
  aI = new ATTRIBINFO [nCols+1];
  for (j=0; j < nCols; j++) {
    aI[j].dType.Clear(); 
    aI[j].iIndex     = -1;
    aI[j].iNull      = -1;
    aI[j].iWidth     = -1;
    aI[j].iPrecision = -1;
    aI[j].iTypeCode  = -1;
    aI[j].iMaxWidth  = -1;
  }

  //
  // Get all of the attributes for this table.
  //


  tableName.Copy(tableNameC);

  ir = _attribSchema->SearchColumn(tableName, _cInASTableName, errCode);
  if ( !ir || ir->Length() <= 0) {
    if (_verbose) _log << "_GetAttributeInfo: No attributes for found for " << tableNameC << endl;
    return(aI);
  }
  if (_verbose) _log << "_GetAttributeInfo: +++ TABLE " << tableNameC << endl << endl;

  nattrib=0;
  for (i=0; i < (int) ir->Length(); i++) {
    row = _attribSchema->GetRow((*ir)[i]);
    if (row) {
      columnName.Clear(); columnName.Copy((*row)[_cInASAttributeName]);

      j = tIn->GetColumnIndex(columnName.Text());      
      if (_verbose) _log << "_GetAttributeInfo: Column [" << j << "] " <<  columnName.Text() << endl;
      if (j >= 0  && j < nCols) {
	aI[j].dType.Clear(); aI[j].dType.Copy((*row)[_cInASDataType]);
	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"char")) {
	  aI[j].iTypeCode = _TYPE_CODE_STRING;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"int")) {
	  aI[j].iTypeCode = _TYPE_CODE_INT;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"float")) {
	  aI[j].iTypeCode = _TYPE_CODE_FLOAT;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"text")) {
	  aI[j].iTypeCode = _TYPE_CODE_TEXT;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"datetime")) {
	  aI[j].iTypeCode = _TYPE_CODE_DATETIME;
	} else 	if ( aI[j].dType.Text()!=NULL &&  !strcasecmp(aI[j].dType.Text(),"bigint")) {
	  aI[j].iTypeCode = _TYPE_CODE_BIGINT;
	}
	
	aI[j].iIndex     = atoi((*row)[_cInASIndexFlag].Text());
	aI[j].iNull      = atoi((*row)[_cInASNullFlag].Text());
	aI[j].iWidth     = atoi((*row)[_cInASWidth].Text());
	aI[j].iPrecision = atoi((*row)[_cInASPrecision].Text());


	if (_verbose) _log << " Width " << aI[j].iWidth << " Type  " << aI[j].iTypeCode 
                           << " Index " << aI[j].iIndex << " Null " << aI[j].iNull << endl;
        nattrib++;
      } 
      delete row;
    }

  }
  if (nattrib < nCols) {
    if (_verbose) _log << "GetAttributeInfo(): warning unmapped column nattrib = " << nattrib  << endl;
  }
  if (_verbose) _log << "_GetAttributeInfo: +++ DONE WITH " << tableNameC << endl << endl;

  delete(ir);
  return(aI);
}



int CifSchemaMap::_CheckMandatoryAttributes(ReVarCifArray<CifString> * row, ATTRIBINFO *aI)
{
  int i, iLen;

  if (row == NULL || aI == NULL) return(0);

  for (i=0; i < (int) row->Length(); i++) {
    if ((aI[i].iNull == 0) && (aI[i].iIndex == 0)) continue;
    iLen = (*row)[i].Length();
    if ( (iLen == 0) || ( ( iLen == 1)  &&  
			  ((*row)[i].Text()[0] == '?' || (*row)[i].Text()[0] == '.') )) return(0);

  }
  return(1);
}

int CifSchemaMap::_CheckNullRow(ReVarCifArray<CifString> * row, ATTRIBINFO *aI)
{
  int i, iLen;

  if (row == NULL || aI == NULL) return(0);

  for (i=0; i < (int) row->Length(); i++) {
    if ((aI[i].iNull == 1) || (aI[i].iIndex == 1)) continue;
    iLen = (*row)[i].Length();
    if ( (iLen == 0) || ( ( iLen == 1)  &&  
			  ((*row)[i].Text()[0] == '?' || (*row)[i].Text()[0] == '.') )) continue;
    return(0);

  }
  return(1);
}

int CifSchemaMap::_CheckIndexAttributes(ReVarCifArray<CifString> * row, ATTRIBINFO *aI)
{
  int i;

  if (row == NULL || aI == NULL) return(0);

  for (i=0; i < (int) row->Length(); i++) {
    if (aI[i].iIndex == 0) continue;
    if ( (*row)[i].Length() == 0 || ( ((*row)[i].Length() == 1)  && 
             ((*row)[i].Text()[0] == '?' || (*row)[i].Text()[0] == '.'))) return(0);

  }
  return(1);
}


void CifSchemaMap::_UpdateTableSQL(ostream &io, ISTable *tIn)
{
  // Update table using the rows of tIn  - SQL version.

  //  ISTable *t = NULL;
  const char *tableNameC  = NULL;

  if (!io)   return;
  if (!tIn ) return;

  tableNameC = tIn->GetName();
  if (tableNameC == NULL || !strlen(tableNameC)) return;

  io << endl;
  io << endl;

  //
  // Get all of the attributes for this table.
  //

  ATTRIBINFO *aI = _GetAttributeInfo(tIn);

  ReVarCifArray<CifString> * row = NULL;
  ReVarCifArray<CifString> * columnNames = NULL;
  int i, j, nRows, nCols, iFirst;

  CifString columnName, columnNameDb, tableName, tableNameDb;
  tableName.Copy(tableNameC);
  _GetTableNameAbbrev(tableNameDb, tableName);

  nRows = tIn->GetNumRows();
  nCols = tIn->GetNumColumns();
  columnNames = tIn->GetColumnNames();

  for (i=0; i < nRows; i++) {

    row = tIn->GetRow(i);
    if (!_CheckMandatoryAttributes(row, aI)) {
      delete row;
      continue;
    }
    if (row) {
      io << endl << endl << "UPDATE " << tableNameDb.Text() << endl;

      io << "SET " << endl;
      
      for (j=0; j < nCols; j++) {

	_GetAttributeNameAbbrev(columnNameDb, tableName, (*columnNames)[j]);

	if (j != 0 ) io << "," << endl;
	switch (aI[j].iTypeCode) {
	case 1: 
	case 2:
	case 6:
	  io << columnNameDb.Text() << " = ";
	  _FormatNumericDataSQL(io, (*row)[j]);
	  break;
	case 3:
	  io << columnNameDb.Text() << " = ";
	  _FormatStringDataSQL(io, (*row)[j], aI[j].iWidth);
	  break;
	case 4:
	  io << columnNameDb.Text() << " = ";
	  _FormatTextDataSQL(io, (*row)[j]);
	  break;
	case 5:
	  io << columnNameDb.Text() << " = ";
	  _FormatDateDataSQL(io, (*row)[j], aI[j].iWidth);
	  break;
	}
      }
      io << endl << "WHERE " << endl;
      iFirst = 0;
      for (j=0; j < nCols; j++) {
	_GetAttributeNameAbbrev(columnNameDb, tableName, (*columnNames)[j]);
	if (aI[j].iIndex) {
	  if (iFirst !=0 ) io << " AND " << endl;
	  iFirst++;
	  switch (aI[j].iTypeCode) {
	  case 1: 
	  case 2:
	  case 6:
	    io << columnNameDb.Text() << " = ";
	    _FormatNumericDataSQL(io, (*row)[j]);
	    break;
	  case 3:
	    io << columnNameDb.Text() << " = ";
            _FormatStringDataSQL(io, (*row)[j], aI[j].iWidth);
	    break;
	  case 4:
	    io << columnNameDb.Text() << " = ";
            _FormatTextDataSQL(io, (*row)[j]);
	    break;
	  case 5:
	    io << columnNameDb.Text() << " = ";
	    _FormatDateDataSQL(io, (*row)[j], aI[j].iWidth);
	    break;
	  }
	}
      }
      io << _cmdTerm << endl;
      delete row;
    }

  }
  delete columnNames;
  delete[] aI;
}



void CifSchemaMap::_DeleteTableSQL(ostream &io, ISTable *tIn)
{
  // Delete table - SQL version.

  const char *tableNameC  = NULL;

  if (!io)   return;
  if (!tIn ) return;

  tableNameC = tIn->GetName();
  if (tableNameC == NULL || !strlen(tableNameC)) return;

  CifString tableName,tableNameDb;
  tableName.Copy(tableNameC);
  _GetTableNameAbbrev(tableNameDb, tableName);

  io << endl;
  io << endl;
  if (_serverType == _SERVER_TYPE_SYBASE) 
    io << "truncate table " << tableNameDb.Text() << _cmdTerm << endl;
  else 
    io << "delete from  " << tableNameDb.Text() << _cmdTerm << endl;
}


void CifSchemaMap::_InsertTableSQL(ostream &io, ISTable *tIn)
{
  // Insert rows of table tIn  - SQL version.

  const char *tableNameC  = NULL;


  if (!io)   return;
  if (!tIn ) return;

  tableNameC = tIn->GetName();
  if (tableNameC == NULL || !strlen(tableNameC)) return;

  //
  // Get all of the attributes for this table.
  //

  ATTRIBINFO *aI = _GetAttributeInfo(tIn);

  ReVarCifArray<CifString> * row = NULL;
  int i, j, nRows, nCols;

  CifString columnName, tableName, tableNameDb;
  tableName.Copy(tableNameC);
  _GetTableNameAbbrev(tableNameDb, tableName);


  nRows = tIn->GetNumRows();
  nCols = tIn->GetNumColumns();

  for (i=0; i < nRows; i++) {

    row = tIn->GetRow(i);
    if (!_CheckMandatoryAttributes(row, aI)) {
      delete row;
      continue;
    }
    if (row) {
      io << endl << endl << "INSERT INTO " << tableNameDb.Text() << endl;

      io << "VALUES (";
      
      for (j=0; j < nCols; j++) {
	if (j != 0 ) io << "," << endl;
	switch (aI[j].iTypeCode) {
	case 1: 
	case 2:
	case 6:
	  _FormatNumericDataSQL(io, (*row)[j]);
	  break;
	case 3:
	  _FormatStringDataSQL(io, (*row)[j], aI[j].iWidth);
	  break;
	case 4:
	  _FormatTextDataSQL(io, (*row)[j]);
	  break;
	case 5:
	  _FormatDateDataSQL(io, (*row)[j], aI[j].iWidth);
	  break;

	}
      }
      io << endl << ")" << _cmdTerm << endl;


      delete row;
    }

  }

  delete[] aI;
}



void CifSchemaMap::_WriteTableBCP(ostream &io, ISTable *tIn)
{
  // Write table using the rows of tIn  - BCP version.

  if (!io || !tIn) return;
  //
  // Get all of the attributes for this table.
  //
  ATTRIBINFO *aI = _GetAttributeInfo(tIn);

  ReVarCifArray<CifString> * row = NULL;
  ReVarCifArray<CifString> * columnNames = NULL;
  int i, j, nRows, nCols, jLen;

  nRows = tIn->GetNumRows();
  nCols = tIn->GetNumColumns();
  columnNames = tIn->GetColumnNames();

  for (i=0; i < nRows; i++) {
    row = tIn->GetRow(i);
    if (_verbose) {
      _log << "BCP writing row " << i << endl;
    }
    // jdwxxxx
    //    if (!_CheckMandatoryAttributes(row, aI) || _CheckNullRow(row, aI) ) {
    if (!_CheckMandatoryAttributes(row, aI) ) {
        if (_verbose) _log << "Failing check on row " << i << endl;
	delete row;
       continue;
    }
    if (row) {
      for (j=0; j < nCols; j++) {
	jLen = (*row)[j].Length();
	if (jLen > aI[j].iMaxWidth)  aI[j].iMaxWidth = jLen;
	if (j != 0 ) io << _fieldSeparator;
	switch (aI[j].iTypeCode) {
	case 1: 
	case 2:
	case 6:
	  _FormatNumericDataBCP(io, (*row)[j]);
	  break;

	case 3:
	  _FormatStringDataBCP(io, (*row)[j], aI[j].iWidth);
	  if (jLen > aI[j].iWidth) {
	    cerr  << "In " << _INPUT_FILE << ": "  
		  << "Table " << tIn->GetName() <<  " column " << (*columnNames)[j].Text() 
		  << " row "  << i   <<  " truncated at " <<  aI[j].iWidth 
		  << " of " << jLen << endl;
	  }
	  break;
	case 4:
	  _FormatTextDataBCP(io, (*row)[j]);
	  break;

	case 5:
	  _FormatStringDataBCP(io, (*row)[j], aI[j].iWidth);
	  break;
	}
      }
      io << _rowSeparator;
      delete row;
    }
  }

  if (_verbose) {
    for (i=0; i < nCols; i++) {
      _log  << tIn->GetName() << " " << (*columnNames)[i].Text() << " " << aI[i].iMaxWidth << endl;
    }
  }
  if (columnNames) delete columnNames;  
  delete[] aI;
}



void CifSchemaMap::_WriteTableBCPdb2(ostream &io, ISTable *tIn)
{
  // Write table using the rows of tIn  - BCP version for DB2.

  if (!io || !tIn) return;
  //
  // Get all of the attributes for this table.
  //
  ATTRIBINFO *aI = _GetAttributeInfo(tIn);

  ReVarCifArray<CifString> * row = NULL;
  ReVarCifArray<CifString> * columnNames = NULL;
  int i, j, nRows, nCols, jLen;

  nRows = tIn->GetNumRows();
  nCols = tIn->GetNumColumns();
  columnNames = tIn->GetColumnNames();

  for (i=0; i < nRows; i++) {
    row = tIn->GetRow(i);
    if (_verbose) {
      _log << "BCP writing row " << i << endl;
    }
    // jdwxxxx
    //    if (!_CheckMandatoryAttributes(row, aI) || _CheckNullRow(row, aI) ) {
    if (!_CheckMandatoryAttributes(row, aI) ) {
        if (_verbose) _log << "Failing check on row " << i << endl;
	delete row;
       continue;
    }
    if (row) {
      for (j=0; j < nCols; j++) {
	jLen = (*row)[j].Length();
	if (jLen > aI[j].iMaxWidth)  aI[j].iMaxWidth = jLen;
	if (j != 0 ) io << _fieldSeparator;
	switch (aI[j].iTypeCode) {
	case 1: 
	case 2:
	case 6:
	  _FormatNumericDataBCP(io, (*row)[j]);
	  break;

	case 3:
	  io << "\"";
	  _FormatStringDataBCPdb2(io, (*row)[j], aI[j].iWidth);
	  io << "\"";
	  if (jLen > aI[j].iWidth) {
	    cerr  << "In " << _INPUT_FILE << ": "  
		  << "Table " << tIn->GetName() <<  " column " << (*columnNames)[j].Text() 
		  << " row "  << i   <<  " truncated at " <<  aI[j].iWidth 
		  << " of " << jLen << endl;
	  }
	  break;
	case 4:
	  io << "\"";
	  _FormatTextDataBCPdb2(io, (*row)[j]);
	  io << "\"";
	  break;

	case 5:
	  //	  io << "\"";
	  _FormatStringDataBCPdb2(io, (*row)[j], aI[j].iWidth);
	  //	  io << "\"";
	  break;
	}
      }
      io << _rowSeparator;
      delete row;
    }
  }

  if (_verbose) {
    for (i=0; i < nCols; i++) {
      _log  << tIn->GetName() << " " << (*columnNames)[i].Text() << " " << aI[i].iMaxWidth << endl;
    }
  }
  if (columnNames) delete columnNames;  
  delete[] aI;
}


void CifSchemaMap::_UpdateXML(CifFileObj *fobj, int flagAppend)
{
  //
  // XML Update for ...

  ISTable *t = NULL;
  // int ilen, nRows, iGroup;
  // char *tName=NULL;
  char *oFile = NULL;
  CifString tableNameDb;
  ofstream ioxml;

  cerr << "Starting cif->xml" << endl;

  if (strlen(_INPUT_FILE)>0) {
    oFile = new char[strlen(_path) + strlen(_INPUT_FILE)  + 5];
    strcpy(oFile,_path);
    strcat(oFile,_INPUT_FILE);
    strcat(oFile,".xml");
  } else {
    oFile = new char[strlen(_path) +  14];
    strcpy(oFile,_path);
    strcat(oFile,"data.xml");
  }
 

  cerr << "CIF->XML for file " << oFile << endl;

  if (flagAppend) {
    ioxml.open(oFile,ios::out|ios::app);
  } else {
    ioxml.open(oFile,ios::out|ios::trunc);
  } 



  ioxml  << "<?xml version=\"1.0\"?>" << endl;
  ioxml <<  "<datablock  xmlns=\"http://deposit.pdb.org/mmcif/pdbx\"" << endl
	<< "             xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" >" << endl;

  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(_cInTSTableName);
  ReVarCifArray<CifString> *groupNames = _tableSchema->GetColumn(_cInTSGroupName);

  // iGroup = 0;
  for (int i=0; i < (int) tableNames->Length(); i++) {

    _GetTableNameAbbrevXML(tableNameDb, (*tableNames)[i]);


    cerr << " Table " << (*tableNames)[i].Text()  << " abbreviation " << tableNameDb.Text() << endl;

    if (!strncmp("pdbx_",(*tableNames)[i].Text(),5)) {
      ioxml <<  "      <category_"  << tableNameDb.Text() 	    << ">" << endl;
      _SetNamespaceDefaultXML("pdbx"); 
    } else if (!strncmp("ndb_",(*tableNames)[i].Text(),4)) {
      ioxml <<  "      <category_" << tableNameDb.Text() << ">" << endl;
      _SetNamespaceDefaultXML("ndb"); 
    } else {
      ioxml <<  "      <category_" << tableNameDb.Text() << ">" << endl;
      _SetNamespaceDefaultXML("mmcif"); 
    }


    t = fobj->GetTablePtr(_blockName, (*tableNames)[i].Text());
    if (t != NULL && t->GetNumRows() > 0) {
      _WriteTableXML(ioxml, t);
    }

    if (!strncmp("pdbx_",(*tableNames)[i].Text(),5)) {
      ioxml <<  "      </category_" << tableNameDb.Text() << ">" << endl;
    } else if (!strncmp("ndb_",(*tableNames)[i].Text(),4)) {
      ioxml <<  "      </category_" << tableNameDb.Text() << ">" << endl;
    } else {
      ioxml <<  "      </category_" << tableNameDb.Text() << ">" << endl;
    }

    //    if ( (i == tableNames->Length()-1) || strcmp((*groupNames)[i].Text(), (*groupNames)[i+1].Text())  ) {
    //          ioxml <<  "   </mmCIF.GROUP." << (*groupNames)[i].Text() << ">" << endl;
    //    }

  }

  ioxml <<  "</datablock>" << endl;
  ioxml.close();
  if (oFile) delete[] (oFile);
  if (tableNames) delete (tableNames);
  if (groupNames) delete (groupNames);

  return;
}

void CifSchemaMap::_WriteTableXML(ostream &io, ISTable *tIn)
{
  // Write table using the rows of tIn  - XML version.

  if (!io || !tIn) return;
  //
  // Get all of the attributes for this table.
  //
  ATTRIBINFO *aI = _GetAttributeInfo(tIn);

  ReVarCifArray<CifString> * row = NULL;
  ReVarCifArray<CifString> * columnNames = NULL;
  int i, j, nRows, nCols, jLen;
  CifString columnNameDb, tableNameDb, tableName;
  const char *tableNameC  = NULL;

  nRows = tIn->GetNumRows();
  nCols = tIn->GetNumColumns();
  columnNames = tIn->GetColumnNames();

  //JDW XXXX
  tableNameC = tIn->GetName();
  tableName.Copy(tableNameC);
  _GetTableNameAbbrevXML(tableNameDb, tableName);

  // Write indices as attibutes...

  for (i=0; i < nRows; i++) {
    row = tIn->GetRow(i);
    if (_verbose) {
      _log << "XML writing row " << i << endl;
    }
    if (!_CheckMandatoryAttributes(row, aI) ) {
        if (_verbose) _log << "Failing check on row " << i << endl;
	delete row;
       continue;
    }

    if (row) {
      io << "         <";
      //      _QualifyNameXML(io,  tIn->GetName() );
      _QualifyNameXML(io,  tableNameDb.Text() );


      for (j=0; j < nCols; j++) {
	if (aI[j].iIndex && strcasecmp((*columnNames)[j].Text(),"structure_id")) {
	  //jdw
	  _GetAttributeNameAbbrevXML(columnNameDb, tableName, (*columnNames)[j]);
	  //

	  io << " ";
	  //	  _QualifyNameXML(io,(*columnNames)[j].Text());
	  _QualifyNameXML(io,columnNameDb.Text());
	  io << "=\"";

	  jLen = (*row)[j].Length();
	  if (jLen > aI[j].iMaxWidth)  aI[j].iMaxWidth = jLen;
	  switch (aI[j].iTypeCode) {
	  case 1: 
	  case 2:
	  case 6:
	    _FormatNumericDataXML(io, (*row)[j]);
	    break;
	    
	  case 3:
	    _FormatStringDataXML(io, (*row)[j], aI[j].iWidth);
	    if (jLen > aI[j].iWidth) {
	      cerr  << "In " << _INPUT_FILE << ": "  
		    << "Table " << tIn->GetName() <<  " column " << (*columnNames)[j].Text() 
		    << " row "  << i   <<  " truncated at " <<  aI[j].iWidth 
		    << " of " << jLen << endl;
	    }
	    break;
	  case 4:
	  case 5:
	    _FormatStringDataXML(io, (*row)[j], aI[j].iWidth);
	    break;
	  }
	  io << "\"";
	}
      }
      io << ">"  << endl;

      // elements here ... check if null beforehand...

      for (j=0; j < nCols; j++) {
	if (!aI[j].iIndex) {
	  _GetAttributeNameAbbrevXML(columnNameDb, tableName, (*columnNames)[j]);
	  io << "            <" ;
	  //	  _QualifyNameXML(io,(*columnNames)[j].Text());
	  _QualifyNameXML(io,columnNameDb.Text());
	  //jdw
	  if (_isElementNullXML( (*row)[j].Text() )) io << " xsi:nil=\"true\" " ;
          io << ">";

	  jLen = (*row)[j].Length();
	  if (jLen > aI[j].iMaxWidth)  aI[j].iMaxWidth = jLen;
	  switch (aI[j].iTypeCode) {
	  case 1: 
	  case 2:
	  case 6:
	    _FormatNumericDataXML(io, (*row)[j]);
	    break;
	    
	  case 3:
	    _FormatStringDataXML(io, (*row)[j], aI[j].iWidth);
	    if (jLen > aI[j].iWidth) {
	      cerr << "In " << _INPUT_FILE << ": "  
		   << "Table " << tIn->GetName() <<  " column " << (*columnNames)[j].Text() 
		    << " row "  << i   <<  " truncated at " <<  aI[j].iWidth 
		    << " of " << jLen << endl;
	    }
	    break;
	  case 4:
	    io << endl;
	    _FormatTextDataXML(io, (*row)[j]);
	    io << endl << "           " ;
	    break;
	  case 5:
	    _FormatStringDataXML(io, (*row)[j], aI[j].iWidth);
	    break;
	  }
	  io << "</";
	  //	  _QualifyNameXML(io,(*columnNames)[j].Text());
	  _QualifyNameXML(io,columnNameDb.Text());
	  io << ">" << endl;
	}
      }

      io << "         </";
      //      _QualifyNameXML(io,tIn->GetName());

      _QualifyNameXML(io,tableNameDb.Text());
      io << ">" << endl;
      delete row;
    }
  }

  if (_verbose) {
    for (i=0; i < nCols; i++) {
      _log  << tIn->GetName() << " " << (*columnNames)[i].Text() << " " << aI[i].iMaxWidth << endl;
    }
  }
  if (columnNames) delete columnNames;  
  delete[] aI;
}

int CifSchemaMap::_isElementNullXML(const char *val)
{
  if ((val == NULL) || (strlen(val) == 0) || ((strlen(val) == 1) && ((val[0] == '.') || (val[0] == '?')))) return(1);
  return 0; 
  
}

#if 0
void CifSchemaMap::_QualifyNameXML(ostream &io,  const char *name) 
{
  if (!strncmp("pdbx_",name,5)) {
    io << "pdbx:" << name;
  } else if (!strncmp("ndb_",name,4)) {
    io << "ndb:" << name;
  } else {
    _GetDefaultNamespaceXML(io);
    io << name;
  }
}
#endif

void CifSchemaMap::_GetDefaultNamespaceXML(ostream &io) 
{
  io << _NS_DEFAULT << ":" ;
}

void CifSchemaMap::_SetNamespaceDefaultXML(const char *name) 
{
  if (name && strlen(name) > 0 ) {
    strcpy(_NS_DEFAULT,name);
  } else
    strcpy(_NS_DEFAULT,"mmcif");
}


void CifSchemaMap::_FormatNumericDataXML(ostream &io,  CifString &cs) 
{
  int len;

  if (cs.Text() == NULL || (cs.Length() == 0) || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  len = cs.Length();
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i])) // skip any white space
      continue;
    else
      io << cs.Text()[i];
  }
}



void CifSchemaMap::_FormatStringDataXML(ostream &io,  CifString &cs, int maxWidth) 
{
  int len;

  // A null string or the special CIF characters are treated as NULL . 
  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    return;
  }

  len = cs.Length();
  if (len > maxWidth) len = maxWidth;
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && i==0) // skip leading white space
      continue;
    else  if (isspace(cs.Text()[i]))   // convert all white space to SPACE
      io << " ";
    else if (cs.Text()[i] == '>' ) 
      io << "&gt;" ;
    else if (cs.Text()[i] =='<' )
      io << "&lt;" ;
    else if (cs.Text()[i] =='\'')  
      io << "&apos;" ;
    else if (cs.Text()[i] =='\"')  
      io << "&quot;" ;
    else if (cs.Text()[i] =='&')  
      io << "&amp;" ;
    else if (cs.Text()[i] =='%')  
      io << "&#37;" ;
    else
      io << cs.Text()[i];
  }
}



void CifSchemaMap::_FormatTextDataXML(ostream &io,  CifString &cs) 
{
  int len;

  // A null string or the special CIF characters are treated as NULL . 
  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    return;
  }

  len = cs.Length();
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && cs.Text()[i] != '\n')   // convert all white space to SPACE
      io << " ";
    else if (cs.Text()[i] == '>' ) 
      io << "&gt;" ;
    else if (cs.Text()[i] =='<' )
      io << "&lt;" ;
    else if (cs.Text()[i] =='\'')  
      io << "&apos;" ;
    else if (cs.Text()[i] =='\"')  
      io << "&quot;" ;
    else if (cs.Text()[i] =='&')  
      io << "&amp;" ;
    else if (cs.Text()[i] =='%')  
      io << "&#37;" ;

    else
      io << cs.Text()[i];
  }
}


void CifSchemaMap::_FormatDateDataXML(ostream &io,  CifString &cs, int maxWidth) 
{
  int len;
  if (cs.Text() == NULL || (cs.Length() == 0) || 
      ((cs.Length() == 1) && (cs.Text()[0] == '?' || cs.Text()[0] == '.'))) {
    return;
  }

  len = cs.Length();
  if (len > maxWidth) len = maxWidth;
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && i==0)
      continue;
    else  if (isspace(cs.Text()[i]))
      io << " ";
    else
      io << cs.Text()[i];
  }
}




void CifSchemaMap::_DeleteRowsSQL(ostream &io, ISTable *tIn)
{
  // Delete rows in table to be replaced by the rows of tIn  - SQL version.
  // Use RCSB Key convention

  //  ISTable *t = NULL;
  const char *tableNameC  = NULL;

  if (!io)   return;
  if (!tIn ) return;

  tableNameC = tIn->GetName();
  if (tableNameC == NULL || !strlen(tableNameC)) return;
  //
  // Get all of the attributes for this table.
  //

  ATTRIBINFO *aI = _GetAttributeInfo(tIn);

  ReVarCifArray<CifString> * row = NULL;
  ReVarCifArray<CifString> * columnNames = NULL;
  int i, j, nRows, nCols, iFirst;

  CifString columnName, tableName;
  tableName.Copy(tableNameC);

  nRows = tIn->GetNumRows();
  nCols = tIn->GetNumColumns();
  columnNames = tIn->GetColumnNames();

  for (i=0; i < nRows; i++) {

    row = tIn->GetRow(i);
    if (!_CheckIndexAttributes(row, aI)) {
      delete row;  
      row = NULL;
      continue;
    }
    if (row) {
      if (_RCSBEXTENSIONS) { // delete primary key col 0
	if ( i > 0){
	  if (row)  {
	    delete row; 
	    row = NULL;
	  }
	  continue;
	}
	io <<"DELETE FROM  " << tableName.Text();
	io << " WHERE " << endl;
	iFirst = 0;

	io << (*columnNames)[0].Text() << " = ";
	_FormatStringDataSQL(io, (*row)[0], aI[0].iWidth);

      } else {
	io << "DELETE FROM  " << tableName.Text();
	io << " WHERE " << endl;
	iFirst = 0;
	for (j=0; j < nCols; j++) {
	  if (aI[j].iIndex) {
	    if (iFirst !=0 ) io << " AND " << endl;
	    iFirst++;
	    switch (aI[j].iTypeCode) {
	    case 1: 
	    case 2:
	    case 6:
	      io << (*columnNames)[j].Text() << " = ";
	      _FormatNumericDataSQL(io, (*row)[j]);
	      break;
	    case 3:
	    case 4:
	      io << (*columnNames)[j].Text() << " = ";
	      _FormatStringDataSQL(io, (*row)[j], aI[j].iWidth);
	      break;
	    case 5:
	      io << (*columnNames)[j].Text() << " = ";
	      _FormatDateDataSQL(io, (*row)[j], aI[j].iWidth);
	      break;
	    }
	  }
	}
      }
      io << _cmdTerm << endl;
    }

    if (row)  {
      delete row; 
      row = NULL;
    }
  }
    if (row)  delete row;
  delete columnNames;
  delete[] aI;
}


void CifSchemaMap::_UpdateBCP(CifFileObj *fobj, int flagAppend)
{
  //
  // BCP Update for ...

  ISTable *t = NULL;
  int ilen, plen,  istat;
  char *tName=NULL;
  ofstream iosql;
  ofstream iobcp;

  struct stat statbuf;


  //  char *fs=NULL, *rs=NULL;
  //  fs = escapeString(_fieldSeparator);
  //  rs = escapeString(_rowSeparator);

  char *oFile = new char[strlen(_path) + strlen(_SQL_FILE) +1];
  strcpy(oFile,_path);
  strcat(oFile,_SQL_FILE);

  if (flagAppend) {
    iosql.open(oFile,ios::out|ios::app);
  } else {
    iosql.open(oFile,ios::out|ios::trunc);
  } 

  if (_serverType != _SERVER_TYPE_ORACLE) {
    iosql << "use " << _dbName << _cmdTerm << endl;
  }
  

  plen=strlen(_path);
  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);

  for (int i=0; i < (int) tableNames->Length(); i++) {
    ilen = strlen((*tableNames)[i].Text());
    if (ilen > 0) {
      tName = new  char[plen + ilen + 15];
      strcpy(tName,_path);
      strcat(tName,(*tableNames)[i].Text());
      strcat(tName,".bcp");
      istat = stat(tName,&statbuf);
      //      cerr << "File size for " << tName << " is " << statbuf.st_size 
      //	   << " istat " << istat << endl;
      while (istat == 0 && statbuf.st_size > _MAXFILESIZE) {
	strcat(tName,"+");
	istat = stat(tName,&statbuf);
	cerr << "File size for " << tName << " is " << statbuf.st_size 
	     << " istat " << istat << endl;
	
      }

      t = fobj->GetTablePtr(_blockName, (*tableNames)[i].Text());
      if (t != NULL && t->GetNumRows() > 0) {

	_DeleteRowsSQL(iosql, t);
        if (flagAppend) {
          iobcp.open(tName,ios::out|ios::app);
        } else {
          iobcp.open(tName,ios::out|ios::trunc);
        } 
	if (_serverType != _SERVER_TYPE_DB2) {
	  _WriteTableBCP(iobcp, t);
	} else {
	  _WriteTableBCPdb2(iobcp, t);
	}

	iobcp.close();
      }
      if (tName) delete[] tName;
    }
  }

  iosql.close();
  if (oFile) delete[] (oFile);
  if (tableNames) delete (tableNames);

  return;
}



void CifSchemaMap::_WriteMysqlLoadFile(int flagAppend)
{
  //
  // LOAD DATA commands for MySQL 

  int ilen, plen, istat;
  char *tName=NULL;
  char *fs=NULL, *rs=NULL;
  struct stat statbuf;
  ofstream iosql;


  fs = escapeString(_fieldSeparator);
  rs = escapeString(_rowSeparator);

  char *oFile = new char[strlen(_path) + strlen(_SQL_FILE) +1];
  strcpy(oFile,_path);
  strcat(oFile,_SQL_FILE);

  if (flagAppend) {
    iosql.open(oFile,ios::out|ios::app);
  } else {
    iosql.open(oFile,ios::out|ios::trunc);
  } 



  iosql << "use " << _dbName << _cmdTerm << endl;

  plen=strlen(_path);
  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);

  for (int i=0; i < (int) tableNames->Length(); i++) {
    ilen = strlen((*tableNames)[i].Text());
    tName = new  char[plen + ilen + 15];
    strcpy(tName,_path);
    strcat(tName,(*tableNames)[i].Text());
    strcat(tName,".bcp");
    istat = stat(tName,&statbuf);
    while (istat == 0 && statbuf.st_size > 0) {

      //      cerr << "File size for " << tName << " is " << statbuf.st_size 
      //	   << " istat " << istat << endl;

      iosql << "LOAD DATA LOCAL INFILE \"" << tName << "\"" << endl
	    << "IGNORE INTO TABLE " << (*tableNames)[i].Text() << endl
	    << "FIELDS TERMINATED BY '" << fs << "'" << endl
	    << "LINES  TERMINATED BY '" << rs << "'" << _cmdTerm << endl;

      strcat(tName,"+");
      istat = stat(tName,&statbuf);      
    }
    if (tName) delete[] tName;
  }

  iosql.close();
  if (oFile) delete[] (oFile);
  if (tableNames) delete (tableNames);

  return;
}


void CifSchemaMap::_UpdateIndicesSQL(void)
{
  //

  int  ilen, plen, istat;
  char *tName=NULL;
  struct stat statbuf;

  char *oFile = new char[strlen(_path) + strlen(_IND_FILE) +1];
  strcpy(oFile,_path);
  strcat(oFile,_IND_FILE);

  ofstream iosql(oFile,ios::out|ios::trunc);

  if (_serverType != _SERVER_TYPE_ORACLE) {
    iosql << "use " << _dbName << _cmdTerm << endl;
  }
 

  plen=strlen(_path);
  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);

  for (int i=0; i < (int) tableNames->Length(); i++) {
    ilen = strlen((*tableNames)[i].Text());
    tName = new  char[plen + ilen + 15];
    strcpy(tName,_path);
    strcat(tName,(*tableNames)[i].Text());
    strcat(tName,".bcp");
    istat = stat(tName,&statbuf);
    if (istat == 0 && statbuf.st_size > 0) {

      //      cerr << "File size for " << tName << " is " << statbuf.st_size 
      //	   << " istat " << istat << endl;

      if (_serverType == _SERVER_TYPE_ORACLE) {
	iosql << "ALTER INDEX I" << (*tableNames)[i].Text() << " REBUILD" << _cmdTerm << endl;
      } else if (_serverType == _SERVER_TYPE_SYBASE) {
	iosql << "UPDATE STATISTICS " << (*tableNames)[i].Text() << _cmdTerm << endl;
      } else if (_serverType == _SERVER_TYPE_DB2) {
	iosql << "UPDATE STATISTICS " << (*tableNames)[i].Text() << _cmdTerm << endl;
      }
    }
    if (tName) delete[] tName;
  }

  iosql.close();
  if (oFile) delete[] (oFile);
  if (tableNames) delete (tableNames);

  return;
}


void CifSchemaMap::_WriteOracleControlFiles(int iAppend)
{
  //
  // Create Oracle 8.1.6 SQLLDR
  //
  // Create control files for all tables in the schema.

  //  ISTable *t = NULL;
  int ilen, plen, istat, i, j,  nCols, errCode, ifirst;
  char *tName=NULL, *oFile=NULL, *bFile=NULL;
  char *fs=NULL, *rs=NULL;
  struct stat statbuf;
  ATTRIBINFO *aI = NULL;
  ReVarCifArray<CifString> * columnNames = NULL;

  ReVarPCifArray<int> * ir = NULL;
  //  ReVarCifArray<CifString> *cList = NULL;
  CifString columnNameDb, tableNameDb;

  if (_verbose) _log << "Starting _WriteOracleControlFiles()" << endl;

  fs = escapeString(_fieldSeparator);
  rs = escapeString(_rowSeparator);



  plen=strlen(_path);
  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);


  for (i=0; i < (int) tableNames->Length(); i++) {
    _GetTableNameAbbrev(tableNameDb, (*tableNames)[i]);
    if (_verbose) _log  << "Writing Oracle control for table "
			<<  tableNameDb.Text() << endl;
    ilen = strlen((*tableNames)[i].Text());

    ir = _attribSchema->SearchColumn((*tableNames)[i],_cInASTableName, errCode);
    if ( !ir || ir->Length() <= 0) {
      continue;
    }
    columnNames = _attribSchema->GetSubColumnByIndex(_cInASAttributeName, ir);
    nCols = columnNames->Length();
    if (_verbose) _log << "Schema defines " << nCols << " attributes " << endl;

    aI = _GetAllAttributeInfo((*tableNames)[i]);


    tName = new  char[plen + ilen + 15];
    strcpy(tName,_path);
    strcat(tName,(*tableNames)[i].Text());
    strcat(tName,".bcp");
    istat = stat(tName,&statbuf);


    oFile = new char[plen + ilen + 15];
    strcpy(oFile,_path);
    strcat(oFile,(*tableNames)[i].Text());
    strcat(oFile,".ctl");
    bFile = new char[plen + ilen + 15];
    strcpy(bFile,_path);
    strcat(bFile,(*tableNames)[i].Text());
    strcat(bFile,".bad");
    ifirst = 1;

    while (ifirst || (istat == 0 && statbuf.st_size > 0) ) {
      if (_verbose) _log << "Writing control file for " << tName << endl;
      ofstream ioctl(oFile,ios::out|ios::trunc);

      ifirst = 0;
      ioctl << "OPTIONS ( ERRORS=100000 )" << endl;
      ioctl << "LOAD DATA" << endl;
      ioctl << "INFILE '" << tName << "'  \"str '" << rs << "'\"" << endl;
      ioctl << "BADFILE '" << bFile <<"'" << endl;
      ioctl << "DISCARDMAX 100000"  << endl;
      
      if (iAppend) 
	ioctl << "APPEND" << endl;
      else 
	ioctl << "TRUNCATE" << endl;
      
      ioctl << "INTO TABLE " << tableNameDb.Text() << endl;
      ioctl << "FIELDS TERMINATED BY '" << fs << "'" << endl;
      ioctl << "TRAILING NULLCOLS" << endl;
      
      
      ioctl << "(";
      
      for (j=0; j < nCols; j++) {
	_GetAttributeNameAbbrev(columnNameDb, (*tableNames)[i], (*columnNames)[j]);
	switch (aI[j].iTypeCode) {
	case 1: 
	case 2:
	case 6:
	  ioctl <<  columnNameDb.Text();
	  break;
	case 3:
	  ioctl <<  columnNameDb.Text() << " char(" <<  aI[j].iWidth  << ")";
	  break;
	case 4:
	  ioctl <<  columnNameDb.Text() << " char(100000)";
	  break;
	case 5:
	  ioctl << columnNameDb.Text() << " date(30) \"YYYY-MM-DD HH24:MI:SS\"";
	  break;
	}
	if (j != nCols-1) ioctl << "," << endl;
      }
      ioctl << ")" << endl << endl;
      ioctl.close();

      // +++++++++++++++++
      strcat(tName,"+");
      istat = stat(tName,&statbuf);
      strcat(oFile,"+");
      strcat(bFile,"+");
    }
    if (columnNames) delete columnNames;
    if (aI) delete[] aI;
    if (oFile) delete[] (oFile);
    if (bFile) delete[] (bFile);
    if (tName) delete[] tName;

  }


  if (tableNames) delete (tableNames);
  
  return;
}


void CifSchemaMap::_WriteDB2ControlFiles(void)
{
  //
  // Create DB2 Configuration Files... 
  //
  // Create config files for all tables in the schema.

  int ilen, plen, istat, i, ifirst;
  char *tName=NULL, *oFile=NULL, *dFile=NULL, *lFile=NULL, *mFile=NULL;
  struct stat statbuf;
  CifString tableNameDb;

  if (_verbose) _log << "Starting _WriteDB2ControlFiles()" << endl;


  plen=strlen(_path);
  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);



  for (i=0; i < (int) tableNames->Length(); i++) {
    _GetTableNameAbbrev(tableNameDb, (*tableNames)[i]);

    if (_verbose) _log  << "Writing DB2 configuration file for table "
			<<  tableNameDb.Text() << endl;

    ilen = strlen((*tableNames)[i].Text());
    tName = new  char[plen + ilen + 15];
    strcpy(tName,_path);
    strcat(tName,(*tableNames)[i].Text());
    strcat(tName,".bcp");
    istat = stat(tName,&statbuf);


    oFile = new char[plen + ilen + 15];
    strcpy(oFile,_path);
    strcat(oFile,(*tableNames)[i].Text());
    strcat(oFile,".cfg");

    dFile = new char[plen + ilen + 15];
    strcpy(dFile,_path);
    strcat(dFile,(*tableNames)[i].Text());
    strcat(dFile,".dmp");

    mFile = new char[plen + ilen + 15];
    strcpy(mFile,_path);
    strcat(mFile,(*tableNames)[i].Text());
    strcat(mFile,".msg");

    lFile = new char[plen + ilen + 15];
    strcpy(lFile,_path);
    strcat(lFile,(*tableNames)[i].Text());
    strcat(lFile,".log");

    ifirst = 1;

    while (ifirst || (istat == 0 && statbuf.st_size > 0) ) {
      if (_verbose) _log << "Writing db2 configuration file for " << tName << endl;
      ofstream ioctl(oFile,ios::out|ios::trunc);

      ifirst = 0;

      ioctl << "RELEASE=V7.2.0" << endl;
      ioctl << "db2 load from " << tName << " of del modified by delprioritychar anyorder ";
      ioctl << " messages " << mFile << " insert into db2inst1.";
      ioctl << tableNameDb.Text() << endl; 
      
      ioctl << "DATABASE=" << _dbName <<  endl;
      ioctl << "OUTPUT_NODES=(0,1,2,3)" << endl;
      ioctl << "MODE=split_and_load" << endl;
      ioctl << "logfile=" <<lFile << endl;
      //      ioctl << "STATUS_INTERVAL=10" <<endl;


      ioctl.close();

      // +++++++++++++++++
      strcat(tName,"+");
      istat = stat(tName,&statbuf);
      strcat(oFile,"+");
      strcat(dFile,"+");
      strcat(mFile,"+");
      strcat(lFile,"+");
    }
    if (oFile) delete[] (oFile);
    if (dFile) delete[] (dFile);
    if (mFile) delete[] (mFile);
    if (lFile) delete[] (lFile);
    if (tName) delete[] tName;

  }
  if (tableNames) delete (tableNames);
  
  return;
}



void CifSchemaMap::_WriteScriptBCP(void)
{
  //
  char *fs=NULL, *rs=NULL;
  ATTRIBINFO *aI = NULL;
  char *oFile = new char[strlen(_path) + strlen(_COMMAND_FILE) + 1];
  strcpy(oFile,_path);
  strcat(oFile,_COMMAND_FILE);
  ofstream io(oFile,ios::out|ios::trunc);

  if (_verbose) {
    _log  << "Write command script for server type " << _serverType << " in file " << oFile << endl;
  }
  if (_serverType == _SERVER_TYPE_SYBASE) {
    fs = escapeString(_fieldSeparator);
    rs = escapeString(_rowSeparator);
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "$SYBASE/bin/isql -U$dbuser -P$dbpw < " <<  _SQL_FILE  << endl;
    io << "#" << endl;
    
    
    ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);
    for (int i=0; i < (int) tableNames->Length(); i++) {
      io << "if ( -e " << (*tableNames)[i].Text() << ".bcp && ! -z " 
	 << (*tableNames)[i].Text() << ".bcp) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      io << "   $SYBASE/bin/bcp " << _dbName << ".." << (*tableNames)[i].Text() << " in " 
	 << (*tableNames)[i].Text() << ".bcp -c -U$dbuser -P$dbpw -b 10000"
	 << " -t '" << fs  << "'" << " -r '" << rs  << "'" << endl;
      io << "endif" << endl;
    }
    if (fs) delete[] fs;   if (rs) delete[] rs;
    if (tableNames) delete tableNames;

    io << "#" << endl;
    io << "if ( -e " << _IND_FILE << " && ! -z " 
	 << _IND_FILE << ") then" << endl;
    io << "     $SYBASE/bin/isql -U$dbuser -P$dbpw < " <<  _IND_FILE  << endl;
    io << "endif" << endl;
    io << "#" << endl;


  } else   if (_serverType == _SERVER_TYPE_MYSQL) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "mysql -f --user=$dbuser --password=$dbpw < " <<  _SQL_FILE  << endl;
    io << "#" << endl;

  } else   if (_serverType == _SERVER_TYPE_DB2) {
    io << "#!/bin/csh -f" << endl;
    io << "#" << endl;
    io << "setenv DB2INSTANCE  db2inst1" << endl;
    //    io << "setenv DB2INSTHOME  /home/db2inst1"   << endl;
    io << "setenv DB2DIR       /usr/IBMdb2/V7.1" << endl;
    io << "setenv DB2COMM      tcpip" << endl;
    io << "#" << endl;
    io << "if ( -e " << _SQL_FILE << " && ! -z " 
	 << _SQL_FILE << ") then" << endl;
    io << "     $DB2DIR/bin/db2 -tf " <<  _SQL_FILE  << endl;
    io << "endif" << endl;

    ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);
    for (int i=0; i < (int) tableNames->Length(); i++) {
      io << "if ( -e " << (*tableNames)[i].Text() << ".bcp && ! -z " 
	 << (*tableNames)[i].Text() << ".bcp) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      io << "   $DB2DIR/bin/db2atld -config " <<  (*tableNames)[i].Text() << ".cfg" << endl;
      io << "endif" << endl;
      //
      io << "if ( -e " << (*tableNames)[i].Text() << ".bcp+ && ! -z " 
	 << (*tableNames)[i].Text() << ".bcp+) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      io << "   $DB2DIR/bin/db2atld -config " <<  (*tableNames)[i].Text() << ".cfg+" << endl;
      io << "endif" << endl;

      io << "if ( -e " << (*tableNames)[i].Text() << ".bcp++ && ! -z " 
	 << (*tableNames)[i].Text() << ".bcp++) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      io << "   $DB2DIR/bin/db2atld -config " <<  (*tableNames)[i].Text() << ".cfg++" << endl;
      io << "endif" << endl;

      io << "if ( -e " << (*tableNames)[i].Text() << ".bcp+++ && ! -z " 
	 << (*tableNames)[i].Text() << ".bcp+++) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      io << "   $DB2DIR/bin/db2atld -config " <<  (*tableNames)[i].Text() << ".cfg++" << endl;
      io << "endif" << endl;


    }
    if (tableNames) delete tableNames;

    io << "#" << endl;

    //    io << "if ( -e " << _IND_FILE << " && ! -z " 
    //	 << _IND_FILE << ") then" << endl;
    //    io << "     $DB2/bin/db2 " <<  _IND_FILE  << endl;
    //    io << "endif" << endl;
    //    io << "#" << endl;

  } else   if (_serverType == _SERVER_TYPE_ORACLE) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "if ( -e " << _SQL_FILE << " && ! -z " 
	 << _SQL_FILE << ") then" << endl;
    io << "     $ORACLE_HOME/bin/sqlplus $dbuser/$dbpw < " << _SQL_FILE << endl;
    io << "endif" << endl;
    io << "#" << endl;

    ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);
    ReVarPCifArray<int> * ir = NULL;
    ReVarCifArray<CifString> *columnNames = NULL;
    int j, errCode, nCols,iText;

    for (int i=0; i < (int) tableNames->Length(); i++) {


      ir = _attribSchema->SearchColumn((*tableNames)[i],_cInASTableName, errCode);
      if ( !ir || ir->Length() <= 0) {
	continue;
      }
      
      columnNames = _attribSchema->GetSubColumnByIndex(_cInASAttributeName, ir);
      nCols = columnNames->Length();
      if (ir) delete ir;

      aI = _GetAllAttributeInfo((*tableNames)[i]);
      iText = 0;
      for (j=0; j<nCols-1; j++) {
	if (aI[j].iTypeCode == _TYPE_CODE_TEXT) {
	  iText = 1; 
          break;
	}
      }

      io << "if ( -e " << (*tableNames)[i].Text() << ".ctl && ! -z " 
	 << (*tableNames)[i].Text() << ".ctl) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      if (iText) 
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl direct=false " <<   endl;
      else
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl direct=true " <<   endl;
      io << "endif" << endl;

      //JDW Temporary Hack to get complete script.
      io << "if ( -e " << (*tableNames)[i].Text() << ".ctl+ && ! -z " 
	 << (*tableNames)[i].Text() << ".ctl+) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      if (iText) 
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl+ direct=false " <<   endl;
      else
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl+ direct=true " <<   endl;
      io << "endif" << endl;

      io << "if ( -e " << (*tableNames)[i].Text() << ".ctl++ && ! -z " 
	 << (*tableNames)[i].Text() << ".ctl++) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      if (iText) 
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl++ direct=false " <<   endl;
      else
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl++ direct=true " <<   endl;
      io << "endif" << endl;

      io << "if ( -e " << (*tableNames)[i].Text() << ".ctl+++ && ! -z " 
	 << (*tableNames)[i].Text() << ".ctl+++) then" << endl;
      io << "   echo \"Loading table " << (*tableNames)[i].Text() << "\" "<< endl;
      if (iText) 
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl+++ direct=false " <<   endl;
      else
	io << "   $ORACLE_HOME/bin/sqlldr  $dbuser/$dbpw " << (*tableNames)[i].Text()  << ".ctl+++ direct=true " <<   endl;
      io << "endif" << endl;


      if (aI) delete[] aI;
      if (columnNames) delete columnNames;
    }

    if (tableNames) delete tableNames;

  
    io << "#" << endl;

    io << "#" << endl;
    io << "if ( -e " << _IND_FILE << " && ! -z " 
	 << _IND_FILE << ") then" << endl;
    io << "     $ORACLE_HOME/bin/sqlplus $dbuser/$dbpw < " << _IND_FILE << endl;
    io << "endif" << endl;
    io << "#" << endl;


  }

  io << endl;
  io.close();

  if (oFile) delete[] oFile;

  return;
}





void CifSchemaMap::_WriteScriptSQL(void)
{
  //
  char *oFile = new char[strlen(_path) + strlen(_COMMAND_FILE) + 1];
  strcpy(oFile,_path);
  strcat(oFile,_COMMAND_FILE);
  ofstream io(oFile,ios::out|ios::trunc);

  if (_serverType == _SERVER_TYPE_SYBASE) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "if ( -e " << _SCHEMA_SQL_FILE << " && ! -z " << _SCHEMA_SQL_FILE << ") then " << endl;
    io << "     $SYBASE/bin/isql -U$dbuser -P$dbpw < " << _SCHEMA_SQL_FILE << endl;
    io << "endif" << endl;
    
    io << "if ( -e " << _SQL_FILE << " && ! -z " << _SQL_FILE << ") then " << endl;
    io << "     $SYBASE/bin/isql -U$dbuser -P$dbpw < " << _SQL_FILE << endl;
    io << "endif" << endl;

  } else   if (_serverType == _SERVER_TYPE_MYSQL) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "if ( -e " << _SCHEMA_SQL_FILE << " && ! -z " << _SCHEMA_SQL_FILE << ") then " << endl;
    io << "     mysql -f --user=$dbuser --password=$dbpw < " << _SCHEMA_SQL_FILE << endl;
    io << "endif" << endl;
    
    io << "if ( -e " << _SQL_FILE << " && ! -z " << _SQL_FILE << ") then " << endl;
    io << "     mysql -f --user=$dbuser --password=$dbpw < " << _SQL_FILE << endl;
    io << "endif" << endl;

  } else   if (_serverType == _SERVER_TYPE_ORACLE) {

  } else   if (_serverType == _SERVER_TYPE_DB2) {

  }

  io << endl;
  io.close();
  if (oFile) delete oFile;
  return;
}


void CifSchemaMap::_WriteScriptSchema(void)
{
  //
  char *oFile = new char[strlen(_path) + strlen(_SCHEMA_COMMAND_FILE) + 1];
  strcpy(oFile,_path);
  strcat(oFile,_SCHEMA_COMMAND_FILE);
  ofstream io(oFile,ios::out|ios::trunc);


  if (_serverType == _SERVER_TYPE_SYBASE) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "if ( -e " << _SCHEMA_SQL_FILE << " && ! -z " << _SCHEMA_SQL_FILE << ") then " << endl;
    io << "     $SYBASE/bin/isql -U$dbuser -P$dbpw < " << _SCHEMA_SQL_FILE << endl;
    io << "endif" << endl;
    io << endl;
  } else if (_serverType == _SERVER_TYPE_MYSQL) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "if ( -e " << _SCHEMA_SQL_FILE << " && ! -z " << _SCHEMA_SQL_FILE << ") then " << endl;
    io << "     mysql -f --user=$dbuser --password=$dbpw < " << _SCHEMA_SQL_FILE << endl;
    io << "endif" << endl;
    io << endl;

  } else if (_serverType == _SERVER_TYPE_DB2) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "if ( -e " << _SCHEMA_SQL_FILE << " && ! -z " << _SCHEMA_SQL_FILE << ") then " << endl;
    io << "     db2 -f --user=$dbuser --password=$dbpw < " << _SCHEMA_SQL_FILE << endl;
    io << "endif" << endl;
    io << endl;

  } else if (_serverType == _SERVER_TYPE_ORACLE) {
    io << "#!/bin/csh -f" << endl;
    io << "set dbuser   = $NDB_XDBUSER" << endl;
    io << "set dbpw     = $NDB_XDBPW"   << endl;
    io << "#" << endl;
    io << "if ( -e " << _SCHEMA_SQL_FILE << " && ! -z " << _SCHEMA_SQL_FILE << ") then " << endl;
    io << "     $ORACLE_HOME/bin/sqlplus $dbuser/$dbpw < " << _SCHEMA_SQL_FILE << endl;
    io << "endif" << endl;
    io << endl;

  }

  io.close();
  if (oFile) delete oFile;
  return;
}





void CifSchemaMap::_UpdateSQL(CifFileObj *fobj, int flagAppend)
{
  //
  // BCP Update for ...
  //
  ISTable *t = NULL;
  ofstream iosql;

  char *oFile = new char[strlen(_path) + strlen(_SQL_FILE) + 1];
  strcpy(oFile,_path);
  strcat(oFile,_SQL_FILE);

  if (flagAppend) {
    iosql.open(oFile,ios::out|ios::app);
  } else {
    iosql.open(oFile,ios::out|ios::trunc);
  } 

  iosql << "use " << _dbName << _cmdTerm << endl;


  ReVarCifArray<CifString> *tableNames = _tableSchema->GetColumn(0);
  for (int i=0; i < (int) tableNames->Length(); i++) {
    t = fobj->GetTablePtr(_blockName, (*tableNames)[i].Text());
    _DeleteRowsSQL(iosql, t);
    _InsertTableSQL(iosql, t);
  }

  iosql.close();
  if (tableNames) delete tableNames;
  if (oFile) delete oFile;
  return;
}



void CifSchemaMap::_FormatNumericDataSQL(ostream &io,  CifString &cs) 
{
  int len;

  if (cs.Text() == NULL || (cs.Length() == 0) || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    io << "NULL";
    return;
  }

  len = cs.Length();
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i])) // skip any white space
      continue;
    else
      io << cs.Text()[i];
  }
}



void CifSchemaMap::_FormatNumericDataBCP(ostream &io,  CifString &cs) 
{
  int len;

  if (cs.Text() == NULL || (cs.Length() == 0) || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  len = cs.Length();
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i])) // skip any white space
      continue;
    else
      io << cs.Text()[i];
  }
}



void CifSchemaMap::_FormatStringDataBCP(ostream &io,  CifString &cs, int maxWidth) 
{
  int len, ifirst;

  // A null string or the special CIF characters are treated as NULL . 
  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    return;
  }
  ifirst = 1;
  len = cs.Length();
  if (len > maxWidth) len = maxWidth;
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && ifirst==1) // skip leading white space
      continue;
    else  if (isspace(cs.Text()[i])) {   // convert all white space to SPACE
      io << " ";
    } else {
      io << cs.Text()[i];
      ifirst = 0;
    }
  }
}



void CifSchemaMap::_FormatStringDataBCPdb2(ostream &io,  CifString &cs, int maxWidth) 
{
  int len, ifirst;
  //   " -> ""

  // A null string or the special CIF characters are treated as NULL . 
  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    return;
  }

  ifirst = 1;
  len = cs.Length();
  if (len > maxWidth) len = maxWidth;
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && ifirst==1) // skip leading white space
      continue;
    else  if (isspace(cs.Text()[i])) {   // convert all white space to SPACE
      io << " ";
    } else  if ( cs.Text()[i] == '"') {   // double up double quotes
      io << "\"\"";
      ifirst = 0;
    } else {
      io << cs.Text()[i];
      ifirst = 0;
    }
  }
}



void CifSchemaMap::_FormatTextDataBCP(ostream &io,  CifString &cs) 
{
  int len;

  // A null string or the special CIF characters are treated as NULL . 
  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    return;
  }

  len = cs.Length();
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && cs.Text()[i] != '\n')   // convert all white space to SPACE
      io << " ";
    else
      io << cs.Text()[i];
  }
}


void CifSchemaMap::_FormatTextDataBCPdb2(ostream &io,  CifString &cs) 
{
  int len;

  // A null string or the special CIF characters are treated as NULL . 

  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    return;
  }

  len = cs.Length();
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && cs.Text()[i] != '\n')   // convert all white space to SPACE
      io << " ";
    else  if ( cs.Text()[i] == '"')   // double-up double quotes
      io << "\"\"";
    else
      io << cs.Text()[i];
  }
}


void CifSchemaMap::_FormatStringDataSQL(ostream &io,  CifString &cs, int maxWidth) 
{
  int len, ifirst;

  // A null string or the special CIF characters are treated as NULL . 
  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    io << "NULL";
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    io << "''";
    return;
  }

  len = cs.Length();
  if (len > maxWidth) len = maxWidth;
  io << "'";
  ifirst = 1;
  for (int i=0; i < len; i++) {
    if (ifirst==1 && isspace(cs.Text()[i]) ) // skip leading white space
      continue;
    else  if (isspace(cs.Text()[i]))         // convert all white space to SPACE
      io << " ";
    else  if (cs.Text()[i] == '\'') {        // double-up single quotes
      io << "''";
      ifirst = 0;
    } else {
      io << cs.Text()[i];
      ifirst = 0;
    }
  }
  io << "'";
}



void CifSchemaMap::_FormatTextDataSQL(ostream &io,  CifString &cs) 
{
  int len;

  // A null string or the special CIF characters are treated as NULL . 
  if (cs.Text() == NULL || 
      ((cs.Length() == 1) && (cs.Text()[0] =='?' || cs.Text()[0] =='.'))) {
    io << "NULL";
    return;
  }

  // A zero length string is treated as BLANK
  if (cs.Text() != NULL && (cs.Length() == 0)) {
    io << "''";
    return;
  }


  len = cs.Length();

  if (_serverType == _SERVER_TYPE_MYSQL) {
    io << "'";
    for (int i=0; i < len; i++) {
      if (isspace(cs.Text()[i]) && cs.Text()[i] != '\n')   // convert all white space to SPACE
	io << " ";
      else if (cs.Text()[i] == '\n')   // escape newlines
	io << "\\n";
      else  if (cs.Text()[i] == '\'') // double-up single  quotes
	io << "''";
      else
	io << cs.Text()[i];
    }
    io << "'";
  } else if (_serverType == _SERVER_TYPE_ORACLE) {
    io << "'";
    for (int i=0; i < len; i++) {
      if (i==0  && cs.Text()[i] == '\n') 
	continue;
      else if (isspace(cs.Text()[i]) && cs.Text()[i] != '\n')   // convert all white space to SPACE
	io << " ";
      else if (cs.Text()[i] == '\n') {   // escape newlines ah la Oracle
	if (cs.Text()[i-1] == '\n')
	  io << " \\" << endl;
	else
	  io << "\\" << endl;
      } else  if (cs.Text()[i] == '\'') // double-up single  quotes
	io << "''";
      else
	io << cs.Text()[i];
    }
    io << "'";

  } else {
    io << "'";
    for (int i=0; i < len; i++) {
      if (isspace(cs.Text()[i]) && cs.Text()[i] != '\n')   // convert all white space to SPACE
	io << " ";
      else  if (cs.Text()[i] == '\'') // double-up single  quotes
	io <<  "''";
      else
	io << cs.Text()[i];
    }
    io << "'";
  }

}


void CifSchemaMap::_FormatDateDataSQL(ostream &io,  CifString &cs, int maxWidth) 
{
  int len, ifirst;

  if (cs.Text() == NULL || (cs.Length() == 0) || 
      ((cs.Length() == 1) && (cs.Text()[0] == '?' || cs.Text()[0] == '.'))) {
    io << "NULL"; 
    return;
  }
  ifirst = 1;
  len = cs.Length();
  if (len > maxWidth) len = maxWidth;
  io << "\'";
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && ifirst==1)
      continue;
    else  if (isspace(cs.Text()[i]))
      io << " ";
    else {
      io << cs.Text()[i];
      ifirst = 0;
    }
  }
  io << "\'";
}



void CifSchemaMap::_FormatDateDataBCP(ostream &io,  CifString &cs, int maxWidth) 
{
  int len, ifirst;
  if (cs.Text() == NULL || (cs.Length() == 0) || 
      ((cs.Length() == 1) && (cs.Text()[0] == '?' || cs.Text()[0] == '.'))) {
    return;
  }

  ifirst = 1;
  len = cs.Length();
  if (len > maxWidth) len = maxWidth;
  for (int i=0; i < len; i++) {
    if (isspace(cs.Text()[i]) && ifirst==1)
      continue;
    else  if (isspace(cs.Text()[i]))
      io << " ";
    else {
      io << cs.Text()[i];
      ifirst=0;
    }
  }
}




ISTable * CifSchemaMap::_CreateTableInfo(CifFileObj *fobj) 
{
  ISTable *tinfo = NULL;
  ISTable *t = NULL;

  t = _tableSchema;

  ReVarCifArray<CifString> *tableNames = t->GetColumn(0);
  ReVarCifArray<CifString> *c1 = t->GetColumn(1);
  ReVarCifArray<CifString> *c2 = t->GetColumn(2);
  ReVarCifArray<CifString> *c3 = t->GetColumn(3);
  ReVarCifArray<CifString> *c4 = t->GetColumn(4);

  ISTable *td = fobj->GetTablePtr("rcsb_schema","rcsb_table_description");

  tinfo = new ISTable("rcsb_tableinfo");

  if (_compatibilityMode==2)  tinfo->AddColumn("Structure_ID", FALSE);

  tinfo->AddColumn("tablename", TRUE);
  tinfo->AddColumn("description", TRUE);
  tinfo->AddColumn("type", TRUE);
  tinfo->AddColumn("table_serial_no", TRUE);
  tinfo->AddColumn("group_name", TRUE);
  tinfo->AddColumn("WWW_Selection_Criteria", TRUE);  
  tinfo->AddColumn("WWW_Report_Criteria", TRUE);  

  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  int errCode;
  CifString cs1, cs2, cs3;
  cs1.Clear(); 
  cs1.Copy("ADDB01");
  
  for (int i=0; i < (int) tableNames->Length(); i++) {
    if (!strcmp((*tableNames)[i].Text(),"tableinfo") || 
	!strcmp((*tableNames)[i].Text(),"columninfo")) continue;
    
    if (_verbose) _log << endl << "_CreateTableInfo  table = " 
		       << (*tableNames)[i].Text() << endl;
    
    cs2.Clear(); cs2 += i+1;
    cs3.Clear();
    ir = td->SearchColumn((*tableNames)[i],0,errCode);
    if (ir && ir->Length() > 0) {
      row = td->GetRow((*ir)[0]);
      if (row) {
	cs3.Copy((*row)[1]);
	delete row;
      }      
    }  else {
      if (_verbose) _log << endl << "_CreateTableInfo  NO information for " 
			   << (*tableNames)[i].Text() << endl;
      // Add default text 
      cs3.Copy("Missing table description");
    }
    tinfo->AddRow();
    if (_compatibilityMode==2) tinfo->AddElementToRow(cs1,i);
    tinfo->AddElementToRow((*tableNames)[i],i);
    tinfo->AddElementToRow(cs3,i);
    tinfo->AddElementToRow((*c1)[i],i);
    tinfo->AddElementToRow(cs2,i);
    tinfo->AddElementToRow((*c2)[i],i);
    tinfo->AddElementToRow((*c3)[i],i);
    tinfo->AddElementToRow((*c4)[i],i);
  }

  //  if (_verbose) {
  //    tinfo->PrintTable();
  //  }

  return(tinfo);
}


ISTable *CifSchemaMap::_CreateColumnInfo(CifFileObj *fobj) 
{
  ISTable *cinfo = NULL;
  ISTable *t = NULL;

  t = _attribSchema;
  ReVarCifArray<CifString> *c0 = t->GetColumn(0);
  ReVarCifArray<CifString> *c1 = t->GetColumn(1);
  //  ReVarCifArray<CifString> *c2 = t->GetColumn(2);
  //  ReVarCifArray<CifString> *c3 = t->GetColumn(3);
  //  ReVarCifArray<CifString> *c4 = t->GetColumn(4);
  //  ReVarCifArray<CifString> *c5 = t->GetColumn(5);
  //  ReVarCifArray<CifString> *c6 = t->GetColumn(6);

  ISTable *td = fobj->GetTablePtr("rcsb_schema","rcsb_attribute_description");

  ISTable *tv = fobj->GetTablePtr("rcsb_schema","rcsb_attribute_view");

  cinfo = new ISTable("rcsb_columninfo");
  if (_compatibilityMode==2) cinfo->AddColumn("Structure_ID", FALSE);
  cinfo->AddColumn("tablename", TRUE);
  cinfo->AddColumn("columnname", TRUE);
  cinfo->AddColumn("description", TRUE);
  cinfo->AddColumn("example", TRUE);
  cinfo->AddColumn("type", TRUE);
  cinfo->AddColumn("table_serial_no", TRUE);
  cinfo->AddColumn("column_serial_no", TRUE);
  cinfo->AddColumn("WWW_Selection_Criteria", TRUE);  
  cinfo->AddColumn("WWW_Report_Criteria", TRUE);  

  ReVarPCifArray<int> * ir = NULL;
  ReVarCifArray<CifString> * row = NULL;
  ReVarCifArray<CifString> * q0 = NULL;
  q0 = new   ReVarCifArray<CifString>;
  ReVarPCifArray<int> * iq0 = NULL;
  iq0 =   new ReVarPCifArray<int>;
  
  int it=0,errCode;
  CifString cs1, cs2, cs3, cs4, cs5, cs6,cs7, cs8;
  cs1.Clear(); 
  cs1.Copy("ADDB01");
  
  for (int i=0; i < (int) c0->Length(); i++) {
    if (!strcmp((*c0)[i].Text(),"tableinfo") || 
	!strcmp((*c0)[i].Text(),"columninfo")) continue;
    if (i > 0 && strcmp((*c0)[i].Text(),(*c0)[i-1].Text())) it++;
    cs8.Clear(); cs8 += it+1;
    cs2.Clear(); cs2 += i+1;
    cs3.Clear(); cs4.Clear();  cs5.Clear(); cs6.Clear(); cs7.Clear();

    q0->Clear(); q0->Add((*c0)[i]); q0->Add((*c1)[i]);
    iq0->Clear(); iq0->Add(0);     iq0->Add(1);
    ir = td->Search(*q0, *iq0, errCode);
    if (ir && ir->Length() > 0) {
      row = td->GetRow((*ir)[0]);
      if (row) {
	cs3.Copy((*row)[2]);
	cs4.Copy((*row)[3]);
	delete row;
      }    
      delete ir;
    } 
    if (cs3.Length() == 0 ) cs3.Copy("Missing column description");
    if (cs4.Length() == 0 ) cs4.Copy("Missing column example");

    q0->Clear(); q0->Add((*c0)[i]); q0->Add((*c1)[i]);
    iq0->Clear(); iq0->Add(0);     iq0->Add(1);
    ir = tv->Search(*q0, *iq0, errCode);
    if (ir && ir->Length() > 0) {
      row = tv->GetRow((*ir)[0]);
      if (row) {
	cs5.Copy((*row)[2]);
	cs6.Copy((*row)[3]);
	cs7.Copy((*row)[4]);
	delete row;
      }      
      delete ir;
    } else {
      cs5.Copy("3");
      cs6.Copy("1");
      cs7.Copy("1");
    }


    cinfo->AddRow(); 
    if (_compatibilityMode==2) cinfo->AddElementToRow(cs1,i);
    cinfo->AddElementToRow((*c0)[i],i);
    cinfo->AddElementToRow((*c1)[i],i);
    cinfo->AddElementToRow(cs3,i); // description
    cinfo->AddElementToRow(cs4,i); // example
    cinfo->AddElementToRow(cs5,i);  // type

    cinfo->AddElementToRow(cs8,i);  // column serial
    cinfo->AddElementToRow(cs2,i);  // column serial
    cinfo->AddElementToRow(cs6,i);  // www select
    cinfo->AddElementToRow(cs7,i);  // www report
  }

  //  if (_verbose) cinfo->PrintTable();
  return(cinfo);
}



int CifSchemaMap::_GetKeywordFromItemName(char keyword[_MAX_NAME_LENGTH], 
					 const char *itemName) 
/* ----------------------------------------------------------------------
   Purpose: CifSchemaMap::_GetKeywordFromItemName(keyword, itemName) 
   
            Get the keyword part of an item name (ie. _<category>.<keyword>)
	    Return 1 for success or 0 otherwise.

 * ---------------------------------------------------------------------- */
{
  int i,j,k,ilen;
  //  if (_verbose) _log << "GetkeywordFromItemName() " << itemName << endl;

  strcpy(keyword,"");
  if (!itemName ||   (ilen=strlen(itemName)) < 3 ) return(0);

  //  if (_verbose) _log << "Item name is " << itemName << " len is " << ilen << endl;  
  for (k=1; k < ilen; k++) {
    if (itemName[k] == '.') break;
  }
  if ((k==1) || (k == ilen)) return(0);
  //  if (_verbose) _log << "k " << k << " ilen " << ilen << endl;

  j=0;
  for (i=k+1; i < ilen; i++) {
    keyword[j] = itemName[i];
    j++;
  }
  keyword[j]='\0';
  return(1);
}



int CifSchemaMap::_GetCategoryNameFromItemName(char categoryName[_MAX_NAME_LENGTH], 
					       const char *itemName) 
/* ----------------------------------------------------------------------
   Purpose: CifSchemaMap::_GetCategoryNameFromItemName(categoryName, itemName) 
   
            Get the category part of an item name (ie. _<category>.<keyword>)
	    Return 1 for success or 0 otherwise.

 * ---------------------------------------------------------------------- */
{

  int i,j;
  //  if (_verbose) _log << "GetCategoryFromItemName() " << itemName << endl;

  strcpy(categoryName,"");
  if (!itemName) return(0);
  
  for (i=1, j=0; i < (int) strlen(itemName); i++) {
    if (itemName[i] != '.') {
      categoryName[j] = itemName[i];
      j++;
    } else {
      break;
    }
  }
  categoryName[j]='\0';
  return(1);
}


void CifSchemaMap::_dformat_1(const char *date, char *odate) {
  // reformat  dd-mmm-yy  to Mon dd, yyyy

  if (odate !=NULL) strcpy (odate,"");
  if (date == NULL ||  date[2] != '-' || date[6] != '-' || strlen(date) != 9) return;



  strncpy(odate,&date[3],3);
  odate[1] = tolower(odate[1]);
  odate[2] = tolower(odate[2]);

  strcat(odate," ");
  strncat(odate,&date[0],2);
  if (odate[4] == '0') odate[4] = ' ';

  strcat(odate," ");
  if (date[7] == '0' || date[7] == '1' || date[7] == '2' || date[7] == '3' || date[7] == '4' || date[7] == '5') {
    strcat(odate,"20");
    strncat(odate,&date[7],2);
  } else {
    strcat(odate,"19");
    strncat(odate,&date[7],2);
  }
}


void CifSchemaMap::_dformat_2(const char *date, char *odate) {
  //
  // reformat  CIF data = yyyy-mm-dd[:00:00]  to Mon dd, yyyy
  //                      2000-01-27  to Jan 27, 2000  odate[13]
  //

  if (odate != NULL) strcpy (odate,"");
  if (date == NULL ||  date[4] != '-' || date[7] != '-' ) return;

  char month[5];
  memset(month, 0 ,5);
  strncpy(month,&date[5],2);




  if (!strcmp(month,"01"))
    strcpy(odate,"Jan ");
  else   if (!strcmp(month,"02"))
    strcpy(odate,"Feb ");
  else   if (!strcmp(month,"03"))
    strcpy(odate,"Mar ");
  else   if (!strcmp(month,"04"))
    strcpy(odate,"Apr ");
  else   if (!strcmp(month,"05"))
    strcpy(odate,"May ");
  else   if (!strcmp(month,"06"))
    strcpy(odate,"Jun ");
  else   if (!strcmp(month,"07"))
    strcpy(odate,"Jul ");
  else   if (!strcmp(month,"08"))
    strcpy(odate,"Aug ");
  else   if (!strcmp(month,"09"))
    strcpy(odate,"Sep ");
  else   if (!strcmp(month,"10"))
    strcpy(odate,"Oct ");
  else   if (!strcmp(month,"11"))
    strcpy(odate,"Nov ");
  else   if (!strcmp(month,"12"))
    strcpy(odate,"Dec ");


  strncat(odate,&date[8],2);
  if (odate[4] == '0') odate[4] = ' ';

  strcat(odate," ");
  strncat(odate,&date[0],4);

}



void CifSchemaMap::_dformat_3(const char *date, char *odate, int shortFlag) {
  //
  // reformat  CIF date = yyyy-mm-dd[:00:00]  to  Sybase date yyyy-Mon-dd hh:mm
  //                      2000-01-27  to 2000-Jan-27 00:00  odate[18]
  //
  int i, iDay, maxDay, year;
  char month[5], day[3];

  if (odate == NULL) return;
  strcpy(odate,"");

  if (date == NULL ||  date[4] != '-' || date[7] != '-' ) {
    if (_verbose) _log << "_dformat3() date format error: " << date << endl;
    return;
  }


  memset(month, 0,5);
  strncpy(month,&date[5],2);


  strcpy (odate,"");
  strncat(odate,&date[0],4);

  for (i=0; i < 4; i++) {
    if (!isdigit(odate[i])) {
      if (_verbose) _log << "_dformat3() year format error: " << date << endl;
      strcpy(odate,"");
      return;
    }
  }

  year = atoi(odate);
  strcat(odate,"-");

  if (!strcmp(month,"01")) {
    strcat(odate,"Jan");
    maxDay = 31;
  }  else   if (!strcmp(month,"02")) {
    strcat(odate,"Feb");
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
         maxDay = 29;
    else maxDay = 28;
  } else   if (!strcmp(month,"03")) {
    strcat(odate,"Mar");
    maxDay = 31;
  } else   if (!strcmp(month,"04")) {
    strcat(odate,"Apr");
    maxDay = 30;
  } else   if (!strcmp(month,"05")) {
    strcat(odate,"May");
    maxDay = 31;
  } else   if (!strcmp(month,"06")) {
    strcat(odate,"Jun");
    maxDay = 30;
  } else   if (!strcmp(month,"07")) {
    strcat(odate,"Jul");
    maxDay = 31;
  } else   if (!strcmp(month,"08")) {
    strcat(odate,"Aug");
    maxDay = 31;
  } else   if (!strcmp(month,"09")) {
    strcat(odate,"Sep");
    maxDay = 30;
  } else   if (!strcmp(month,"10")) {
    strcat(odate,"Oct");
    maxDay = 31;
  } else   if (!strcmp(month,"11")) {
    strcat(odate,"Nov");
    maxDay = 30;
  } else   if (!strcmp(month,"12")) {
    strcat(odate,"Dec");
    maxDay = 31;
  } else {  //
    if (_verbose) _log << "_dformat3() month format error: " << date << endl;
    strcpy(odate,"");
    return;
  }




  strcat(odate,"-");
  strncat(odate,&date[8],2);

  if (!isdigit(odate[9]) || !isdigit(odate[10])) {
    if (_verbose) _log << "_dformat3() day format error: " << date << endl;
    strcpy(odate,"");
    return;
  }
  
  day[0] = odate[9];
  day[1] = odate[10];
  day[2] = '\0';
  iDay = atoi(day);
  if ((iDay <= 0) || (iDay > maxDay)) {
    if (_verbose) _log << "_dformat3() day format error: " << date << endl;
    strcpy(odate,"");
    return;
  }

  if (!shortFlag) strcat(odate," 00:00");
}


void CifSchemaMap::_dformat_4(const char *date, char *odate) {
  //
  // Mon dd yyyy to CIF date yyyy-mm-dd  odate[11]
  //
  if (odate == NULL) return;
  strcpy(odate,"");

  if (date == NULL ||  date[3] != ' ' || date[6] != ' ' ) return;

  char month[5];
  memset(month, 0 ,5);
  strncpy(month,date,3);


  strcpy (odate,"");
  strncat(odate,&date[7],4);
  strcat(odate,"-");

  if (!strcmp(month,"Jan"))
    strcat(odate,"01");
  else   if (!strcmp(month,"Feb"))
    strcat(odate,"02");
  else   if (!strcmp(month,"Mar"))
    strcat(odate,"03");
  else   if (!strcmp(month,"Apr"))
    strcat(odate,"04");
  else   if (!strcmp(month,"May"))
    strcat(odate,"05");
  else   if (!strcmp(month,"Jun"))
    strcat(odate,"06");
  else   if (!strcmp(month,"Jul"))
    strcat(odate,"07");
  else   if (!strcmp(month,"Aug"))
    strcat(odate,"08");
  else   if (!strcmp(month,"Sep"))
    strcat(odate,"09");
  else   if (!strcmp(month,"Oct"))
    strcat(odate,"10");
  else   if (!strcmp(month,"Nov"))
    strcat(odate,"11");
  else   if (!strcmp(month,"Dec"))
    strcat(odate,"12");

  strcat(odate,"-");
  strncat(odate,&date[4],2);
  if (odate[8] ==  ' ') odate[8] = '0';

}




void CifSchemaMap::_dformat_5(const char *date, char *odate) {
  //
  // reformat  CIF date = yyyy[-mm-dd:00:00]  to  Oracle/DB2 date yyyy-mm-dd
  //                      2000-01  to 2000-01-01   odate[10]
  //
  int i;

  if (odate == NULL) return;
  strcpy(odate,"");

  if (date == NULL || (strlen(date) < 4) ) {
    if (_verbose) _log << "_dformat_5() date format error" << endl;
    return;
  }

  // Year 
  strncat(odate,&date[0],4);
  for (i=0; i < 4; i++) {
    if (!isdigit(odate[i])) {
      if (_verbose) _log << "_dformat_5() year format error: " << date << endl;
      strcpy(odate,"");
      return;
    }
  }

  //month and day

  if (strlen(date) == 4) {
    strcat(odate,"-01-01");
    return;
  } else if ((strlen(date) == 7) && isdigit(date[5]) && isdigit(date[6])) {
    strcat(odate,"-");
    strncat(odate,&date[5],2);
    strcat(odate,"-01");
    return;
  } else if ((strlen(date) >= 10) && isdigit(date[8]) && isdigit(date[9])) {
    strcat(odate,"-");
    strncat(odate,&date[5],2);
    strcat(odate,"-");
    strncat(odate,&date[8],2);
    return;
  }
}



void CifSchemaMap::_ReorderName(char *string, int mode)
{  
  //  mode = 1. Reformat name:  Lastname, I.J. -> I.J. Lastname
  //  mode = 2. Reformat name:  I.J. Lastname  -> Lastname, I.J. 
  
  if (string == NULL || string[0] == '\0') return;
  
  int i, ilen = 0, c='\0';
  ilen = strlen(string);
  if (ilen < 1) return;


  char *first = new char[ilen+1]; 
  char *last  = new char[ilen+1]; 
  
  if (mode == 1) {
    for (i = strlen(string) - 1; i >= 0; i--)
      if (string[i] == ',') break;
    
    if (i > 0) {
      strcpy(first, &string[i+1]);
      string[i] = '\0';
      strcpy(last, string);
      _CleanString(first);
      _CleanString(last);
      if (first[strlen(first)-1] == '.')
	sprintf(string, "%s%s%c", first, last,c);
      else 
	sprintf(string, "%s %s%c", first, last, c);
    }
    delete first;
    delete last;
    return;
    
  } else if (mode == 2) {
    for (i = strlen(string) - 1; i >= 0; i--) {
      if (string[i] == '.') break;
    }

    if (i > 0) {
      strcpy(last, &string[i+1]);
      string[i+1] = '\0';
      strcpy(first, string);
      sprintf(string, "%s, %s%c", last, first,c);
      _CleanString(string);
      delete first;
      delete last;
      return;
    }
    
    for (i = strlen(string) - 1; i >= 0; i--)
      if (string[i] == ' ') break;
    
    if (i > 0) {
      strcpy(last, &string[i+1]);
      string[i+1] = '\0';
      strcpy(first, string);
      sprintf(string, "%s, %s%c", last, first, c);
      _CleanString(string);
    }
    delete first;
    delete last;
    return;
  }
}  


void CifSchemaMap::_CleanString(char *string)
{
/*
 *  _CleanString() strip leading and trailing white space from a string.
 *  Also compress multiple internal white space characters.
 *
 */

  int i, stringlen;

  if (string == NULL) return;
  stringlen = strlen(string);
  for (i=0; i< stringlen; i++) { 
    if (string[i] == ' ' || string[i] == '\t' ||  string[i] == '\n') {
      strcpy(string, &string[i+1]);	
      stringlen--;
      i--;
    }
    else break;
  }
  for (i=0; i< stringlen; i++) {
    if (i != 0 && 
	(string[i-1] == ' ' || string[i-1] == '\t' || string[i-1] == '\n')  && 
	(string[i]   == ' ' || string[i]   == '\t' || string[i]   == '\n' )) {
      strcpy(&string[i-1], &string[i]);
      i--;
      stringlen--;
    }
  }
  stringlen = strlen(string);
  for (i=0; i< stringlen; i++) {
    if (string[i] == '\t' || string[i] == '\n' ) {
      string[i] = ' ';
    }
  }
  for (i=stringlen -1; i>= 0; i--) {
    if (string[i] == ' ' || string[i] == '\t' ||  string[i] == '\n')
      string[i] = '\0';
    else break;
  }
}


void CifSchemaMap::_ToUpperString(char *string)
{
/*
 *  _ToUpperString() set string to upper case.
 *
 */

  int i;
  if (_verbose) _log << "_ToUpperString: " << string << endl;
  if (string == NULL) return;
  for (i=0; i< (int) strlen(string); i++) { 
    string[i] = toupper(string[i]);
  }
  if (_verbose) _log << "_ToUpperString: " << string << endl;
}

void CifSchemaMap::_StripString(char *string, int mode)
{
/*
 *  _StripString() remove white space characters.  
 *        mode = 1  - all white space
 *        mode = 2  - remove only \n and \r
 */

  int i, j, iLen;
  char *ostring=NULL;
  if (_verbose) _log << "_StripString: input " << string << endl;

  if (string == NULL) return;

  iLen = strlen(string);
  ostring = new char[iLen + 1];
  memset(ostring,'\0',iLen+1);

  j=0;
  if (mode == 1) {
    for (i=0; i< iLen; i++) { 
      if ( isspace(string[i]) ) continue;
      ostring[j] = string[i]; j++;
    }
  } else if (mode == 2) {
    for (i=0; i< iLen; i++) { 
      if ( string[i] == '\n' || string[i] == '\r'  ) continue;
      ostring[j] = string[i]; j++;
    }

  }
  strcpy(string,ostring);
  if (_verbose) _log << "_StripString: output " << string << endl;
  if (ostring) delete[] ostring;
  return;
}

static char *escapeString(const char *inStr) {
  char *outStr = NULL;
  int i, j, iLen;

  if (inStr == NULL) return outStr;
  
  iLen = strlen(inStr);
  outStr = new char[ iLen + iLen + 2];
  memset(outStr,'\0',iLen+iLen+2);
  j = 0;
  for (i=0; i < iLen; i++) {
    if (inStr[i] == '\r') {
      outStr[j] = '\\'; j++;   outStr[j] = 'r'; j++;
    } else if (inStr[i] == '\n') {
      outStr[j] = '\\'; j++;   outStr[j] = 'n'; j++;
    } else if (inStr[i] == '\t') {
      outStr[j] = '\\'; j++;   outStr[j] = 't'; j++;
    } else 
      outStr[j] = inStr[i]; j++;
  }
  outStr[j] = '\0';
  return(outStr);
  
}

static char *_get_attribute_value_where(CifFileObj *fobj, const char *blockId, const char *category, 
				const char *attributeA, const char *attributeB, const char *valB)
{
  ISTable *t=NULL;

  ReVarCifArray<CifString> *col=NULL;
  ReVarPCifArray<int>  *iResult=NULL;
  int nRow, iCol1, iCol2, errCode;
  char *string=NULL;
  CifString cs;

  t=fobj->GetTablePtr(blockId,category);

  if (t != NULL) {
    nRow = t->GetNumRows();
    if (nRow > 0) {
      iCol1 = t->GetColumnIndex(attributeB);
      iCol2 = t->GetColumnIndex(attributeA);

      cs.Clear(); cs.Copy(valB);
      iResult = t->SearchColumn(cs, iCol1, errCode);
      if (!errCode && iResult && (iResult->Length() > 0)) {
	col = t->GetSubRow((*iResult)[0],iCol2, iCol2);
	string = new char[(*col)[0].Length() + 1];
	strcpy(string,(*col)[0].Text());

      } else {

      }
    }
  }
  return(string);
}


#if 0
static void format_text(char *text, int width)
{
  int i, ibeg, iend;

  if ((strlen(text) == 1) && text[0] == '?') {
    printf("?\n");
    return;
  }

  if (strlen(text) < width) {
    printf(";    ");
    for (i=0; i < strlen(text); i++ ) {
      printf("%c", toupper(text[i]));
    }
    printf("\n;\n");
    return;
  }    

  //  printf(" strlen %d \n",strlen(text));

  // Remove newlines... 
  //
  for (i=0; i < strlen(text); i++) {
    if (text[i] == '\n') text[i] = ' ';
  }


  ibeg = 0;
  printf(";");
  while (ibeg < strlen(text)-1) {
    iend = ibeg + width; 
    if (iend >= strlen(text) - 1) {
      iend = strlen(text) -1;

    } else {
      
      //      printf(" ibeg = %d iend = %d \n",ibeg,iend);
      
      while ((iend >= ibeg ) && text[iend] != ' ' && text[iend] != ',' ) {
	--iend;
      }
    }

    //    printf("Adjust ibeg = %d iend = %d \n",ibeg,iend);

    printf("   ");
    for (i=ibeg; i <= iend; i++) {
      printf("%c",toupper(text[i]));
    }
    printf("\n");
    ibeg = iend;
  }
  printf(";\n");
}
//



#endif


