blob: a531e1706c200a39f0d2c6f33e02fdf9ab0deb9f [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
#include <iostream>
#include "ApplicationFile.h"
#include "Cmdline_Args.h"
#include "ComDiags.h"
#include "DgBaseType.h"
#include "ELFFile.h"
#include "NAAssert.h"
#include "SQLJFile.h"
#include "mxCompileUserModule.h"
// factory method (or virtual constructor)
ApplicationFile* ApplicationFile::makeApplicationFile(std::string& filename)
{
// on NT/Win2K/XP, pretend it's an ELF file. SQLJ is not yet on NT.
return new ELFFile(filename);
}
// constructor
ApplicationFile::ApplicationFile(std::string &filename)
: fileName_(filename), nCompiles_(0), nFailures_(0), args_(NULL)
, appFile_(NULL)
{
}
// destructor
ApplicationFile::~ApplicationFile()
{
}
// open application file for reading. return true if all OK.
// NB: It seems illogical to name this method "openFile" when it does not
// open any file at all. However, the classes ApplicationFile, ELFFile,
// SQLJFile and mxCompileUserModuleMain.cpp implement an instance of the
// Factory design pattern. The makeApplicationFile() returns a pointer to
// an ApplicationFile (either an ELFFile or a SQLJFile instance) appFile
// and main() simply calls appFile->openFile(), appFile->closFile(),
// appFile->processModule(), and so on, relying on these virtual functions
// to invoke the appropriate instance of these methods to make it work.
bool ApplicationFile::openFile(Cmdline_Args &args)
{
args_ = &args;
return appFile_ != NULL;
}
// close application file
bool ApplicationFile::closeFile() // return true if all OK
{
bool result = fclose(appFile_) == 0;
appFile_ = NULL;
return result;
}
// create a temporary file name that is not the name of an existing file.
// requires: allocated length of tNam >= L_tmpnam+10.
// returns : tNam if all OK; NULL otherwise.
char* ApplicationFile::getTempFileName(char *tNam)
{
// create temporary file name
char tempName[L_tmpnam], *tmp;
tmp = tmpnam(tempName);
if (!tmp) {
*mxCUMptr << FAIL << DgSqlCode(-2205);
return tmp;
}
else {
// use tempName || ourProcessID as the temporary file name
char pid[20];
sprintf(pid, "%0d", _getpid());
strcpy(tNam, tmp);
strcat(tNam, pid);
return tNam;
}
}
// invoke mxcmp on module definition file
bool ApplicationFile::mxcmpModule(char *mdf)
{
nCompiles_++;
char cmd[1024], *cmdP=cmd, *mxcmp = getenv("MXCMP");
#define DEFAULT_MXCMP "tdm_arkcmp"
mxcmp = mxcmp ? mxcmp : DEFAULT_MXCMP;
// make sure we have enough space for the mxcmp invocation string
assert(args_ != NULL);
Int32 cmdLen = strlen(mxcmp)+args_->application().length()+
args_->otherArgs().length()+strlen(mdf)+7;
// for efficiency we try to use the stack-allocated cmd variable.
// but, no matter how big we declare it, eg: char cmd[12345],
// it is always possible for someone like QA try something like
// mxCompileUserModule -d CQD1=v1 -d CQD2=v2 ... -d CQDn=vn my.exe
// whereby the mxcmp invocation string overflows cmd. We can always
// dynamically allocate and use cmdP but "new" is very inefficient
// compared to stack allocation. So, we try to get the best of both
// by using stack allocation for the 90% case and use "new" only for
// the pathological 10% (customer is using a program generator to
// invoke us or QA is simply trying to break our code) case.
if (cmdLen > 1024) {
cmdP = new char[cmdLen];
// mxCompileUserModuleMain.cpp already did set_new_handler(), so
// if this new fails, mainNewHandler() will handle that exception.
}
if (!cmdP) {
// coverity flags a REVERSE_INULL cid on cmdP -- it's complaining
// we're not checking that cmdP is non-null. So, we oblige.
nFailures_++;
return false;
}
strcpy(cmdP, mxcmp);
strcat(cmdP, " ");
strcat(cmdP, args_->otherArgs().c_str());
strcat(cmdP, " ");
strcat(cmdP, mdf);
cout << cmdP << endl;
Int32 rc = system(cmdP);
// free any space used by mxcmp invocation string
if (cmdP && cmdP != cmd) {
delete cmdP;
}
if (rc == 0) { // success
if (!args_->keepMdf()) {
remove(mdf);
}
}
else if (rc == -1
) {
// function fails: cannot create child process
// or cannot get child shell's exit status
*mxCUMptr << FAIL << DgSqlCode(-2221) << DgInt0(rc);
nFailures_++;
}
else { // unsuccessful mxcmp invocation
Int32 sqlcode, int0;
mxcmpExitCode retcode;
int0 = rc;
retcode = ERROR; // cannot tell ERROR from WARNING on NT
sqlcode = 2201;
*mxCUMptr << retcode << DgSqlCode(-sqlcode) << DgInt0(int0);
nFailures_++;
}
return rc==0;
}
// print summary statistics
void ApplicationFile::printSummary()
{
cout << modulesFound() << " modules found, "
<< modulesExtracted() << " modules extracted." << endl
<< nCompiles_ << " mxcmp invocations: "
<< nCompiles_-nFailures_ << " succeeded, "
<< nFailures_ << " failed." << endl;
}