blob: 3a40e482042b6da6e3db7de597c267356448f6b4 [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 @@@
**********************************************************************/
/* -*-C++-*-
******************************************************************************
*
* File: cmpargs.C
* Created:
* Language: C++
*
*
*
*
******************************************************************************
*/
#include "Platform.h"
#include <ctype.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmpargs.h"
#include "NAExit.h"
#include "SchemaDB.h"
#include "CmpErrors.h"
#include "ErrorMessage.h"
// In order to support template instantiation for TANDEM builds (using
// c89), we conditionally include cmp_templ.C. Furthermore, we
// #define a special macro, __CMP_TMPL_INCLUDED so that
// we obtain the template implementation code from that file.
//
static ostream &operator<<(ostream &dest, ComDiagsArea& diags)
{
NADumpDiags(dest, &diags, FALSE, NO_COMMENT /*info msg style*/);
return dest;
}
static void printCmdline(Int32 argc, char **argv)
{
static char TDM_ARKCMP[] = "tdm_arkcmp";
if (argc == 0 || argv[0] == NULL || argv[0][0] == '\0')
{
if (argc == 0) argc = 1;
argv[0] = TDM_ARKCMP;
}
for (Int32 i = 0; i < argc; i++)
{
if (i) cout << ' ';
cout << argv[i];
}
cout << endl;
}
// process -g {moduleGlobal|moduleLocal}
Int32 Cmdline_Args::doModuleGlobalLocal(char *arg, Int32 argc, char **argv, ComDiagsArea& diags)
{
Int32 result=0;
if (!strcmp(arg, "moduleGlobal")) {
modulePlacement_ = MOD_GLOBAL;
}
else if (!strcmp(arg, "moduleLocal")) {
modulePlacement_ = MOD_LOCAL;
}
else if (!strlen(arg)) {
diags << DgSqlCode(mxcmpUmOptionGargumentMissing); cout << diags;
usage(argc, argv);
result = -1;
}
else {
diags << DgSqlCode(mxcmpUmOptionGargumentUnrecognized); cout << diags;
usage(argc, argv);
result = -1;
}
return result;
}
// process -g {moduleGlobal|moduleLocal[=OSSdirectory]}
Int32 Cmdline_Args::doModuleGlobalLocalDir(char *arg, Int32 argc, char **argv,
Int32 &gCount, ComDiagsArea& diags)
{
Int32 result = 0;
// at most one -g moduleBlah option is allowed
if (gCount > 0) {
diags << DgSqlCode(mxcmpUmAtMostOneoptionGisAllowed); cout << diags;
usage(argc, argv);
result = -1;
}
gCount++;
// process -g {moduleGlobal|moduleLocal}
char *eq = strchr(arg, '=');
if (!eq) { // -g {moduleGlobal|moduleLocal}
return doModuleGlobalLocal(arg, argc, argv, diags);
}
// else -g moduleLocal=OSSdirectory
if (strlen(eq+1) >= 1024) { // OSSdirectory is too long
diags << DgSqlCode(mxcmpUmOssDirectoryPathTooLong) << DgString0(eq+1); cout << diags;
usage(argc, argv);
result = -1;
}
else { // OSSdirectory < 1024
// verify we have -g moduleLocal=OSSdirectory
Int32 kwdLen=(Int32)strlen("moduleLocal");
if (eq-arg == kwdLen && strncmp(arg,"moduleLocal",kwdLen)==0) {
modulePlacement_ = MOD_LOCAL;
// reject any Expand or Guardian path
if (!strncmp(eq+1,"/E/",3) || !strncmp(eq+1,"/G/",3)) {
diags << DgSqlCode(mxcmpUmModuleLocalSpecifyDir); cout << diags;
usage(argc, argv);
result = -1;
}
else {
// copy OSSdirectory
moduleDir_ = eq+1;
}
}
else {
diags << DgSqlCode(mxcmpUmUnsupportedArgumentInOptionG); cout << diags;
usage(argc, argv);
result = -1;
}
}
return result;
}
char* Cmdline_Args::getModuleDir() const
{
if (moduleLocal()) {
return CONST_CAST(char*,moduleDir_.data()); // use this local directory
}
else {
// use global USERMODULES directory. What we want to do here is
// return "/usr/tandem/sqlmx/USERMODULES/";
// But, unfortunately, our caller will pass our return value to
// ComRtGetModuleFileName(modulename, moduledir, ...) whose logic
// relies on a null moduledir to compute the global module directory.
// So, we are forced to do
return NULL;
// Otherwise, mxcmp may place the module in /usr/tandem/sqlmx/USERMODULES
// whereas the debug version of the executor may look for it in the
// SQLMX_MODULE_DIR environment variable setting and the result is an
// error 8809 (unable to open the module file).
}
}
bool Cmdline_Args::moduleLocal() const
{
return FALSE;
}
static void DisplayDebugBox()
{
Int32 pid = getpid();
char stmp[256];
snprintf(stmp, sizeof(stmp), "Process Launched %d", pid);
MessageBox(NULL, stmp , "MXCMP", MB_OK|MB_ICONINFORMATION);
}
Cmdline_Args::Cmdline_Args()
: modulePlacement_(NOT_SET),
moduleDir_("."), // local module dir defaults to current dir
application_(),
moddef_(),
module_(),
isStat_(FALSE), // static compile with mdf name
hasListing_(FALSE),
isVerbose_(FALSE),
ignoreErrors_(FALSE),
allocMethod_(IPC_ALLOC_DONT_CARE),
socketArg_(0),
portArg_(0),
settings_(NULL), // This NAArray goes on system heap. NULL for heap*
noSeabaseDefTableRead_(FALSE)
{}
void Cmdline_Args::processArgs(Int32 argc, char **argv)
{
Space localHeap;
ComDiagsArea diags(&localHeap);
// The following GUI code is to start up arkcmp process into debug
// only if you want to go into debug mode before the arguments are parsed.
if (getenv("SQL_CMP_MSGBOX_PROCESS"))
MessageBox(NULL, "Process Launched", "tdm_arkcmp", MB_OK|MB_ICONINFORMATION);
#ifndef NDEBUG
if (getenv("ARKCMP_ARGS_ECHO"))
{
// We'll output ">> sh tdm_arkcmp -fooOptions arg" (a la sqlci, regress)
cout << ">> sh ";
printCmdline(argc, argv);
}
#endif
Int32 extraArgs = 0;
for ( Int32 i=1; i < argc; i++ ) // start at 1 (args) not 0 (progname)
{
if (!argv[i]) continue;
if (strcmp(argv[i], "-debug") == 0)
{
DisplayDebugBox();
}
else if (strcmp("-fork", argv[i]) == 0)
{
allocMethod_ = IPC_POSIX_FORK_EXEC;
}
else if (strcmp("-service", argv[i]) == 0)
{
// /etc/inetd.conf must be configured with the "-service" option
allocMethod_ = IPC_INETD;
}
else if (strcmp(argv[i], "-oss") == 0)
{
allocMethod_ = IPC_SPAWN_OSS_PROCESS;
}
else if (strcmp("-guardian", argv[i]) == 0)
{
allocMethod_ = IPC_LAUNCH_GUARDIAN_PROCESS;
}
else if (strcmp(argv[i], "-##") == 0) {
if (!extraArgs) extraArgs = -1;
break;
}
else if (strcmp(argv[i], "-noSeabaseDefTableRead") == 0)
{
noSeabaseDefTableRead_ = true;
}
else
extraArgs++;
}
if (allocMethod_ != IPC_ALLOC_DONT_CARE || socketArg_) {
if (extraArgs == 0) { // arkcmp -socket s p
return;
}
else if (extraArgs > 0) { // arkcmp -mModuleX -socket -v (stmt="ocket")
allocMethod_ = IPC_ALLOC_DONT_CARE;
socketArg_ = portArg_ = 0;
}
else { // arkcmp -socket s p -## -mModuleX -sOcket -v
// TODO: need to init getopt such that optind points at (past?)
// this "-##" demarcator ...
}
}
if (argc <= 1) usage(argc, argv); // no "?" errmsg, just this helpful info
Int32 ch, gCount=0;
while ((ch = getopt(argc, argv, "a:d:eg:h?l:v")) != -1) {
switch (ch)
{
case 'a': // application
application_ = optarg;
isStat_ = TRUE;
break;
case 'd': // -d default_attrib=default_value
{
NAString nam(optarg);
// find the = if it exists
Int32 loopx = 0, len = nam.length();
while((loopx < len) && ((nam)(loopx) != '=') )loopx++;
if (len == loopx) {
diags << DgSqlCode(mxcmpUmIllformatedOptionD) << DgString0(optarg);
cout << diags;
usage(argc, argv);
}
else {
// do substring copy of default attribute value
NAString val = (nam)(loopx+1,len-loopx-1);
// do substring copy of default attribute name
nam = (nam)(0,loopx);
// compose default attribute name & value into a ControlSetting
ControlSetting s(nam, val);
addSetting(s); // add ControlSetting to our collection. this
// should make a copy. we wish to create this collection in the
// stmt heap but stmt heap is not yet created at this point.
}
break;
}
case 'e': // ignore errors, return as warnings.
ignoreErrors_ = TRUE;
isStat_ = TRUE;
break;
case 'g': // moduleglobal or modulelocal
doModuleGlobalLocalDir(optarg, argc, argv, gCount, diags);
break;
case 'h':
case '?':
usage(0, NULL); // display nice help message
break;
case 'l': // listing is turned on
hasListing_ = TRUE;
isStat_ = TRUE;
break;
case 'v':
isVerbose_ = TRUE;
break;
default:
{
char buf[2];
buf[0] = (char)ch; buf[1] = 0;
diags << DgSqlCode(mxcmpUmNoCaseForOption) << DgString0(buf) << DgInt1((Int32)ch);
cout << diags;
usage(argc, argv);
}
} // switch
} // while
Int32 sane = TRUE;
if (optind < argc)
{
if (optind < argc-1)
{
diags << DgSqlCode(mxcmpUmTooManyArgumentsOrOptionsIllplaced); cout << diags;
usage(argc, argv);
}
moddef_ = argv[optind];
isStat_ = TRUE;
}
if ( isVerbose_ )
printArgs();
// Sanity checks. Keep in sync with the code above AND with the
// very helpful usage() output below!
//
if (isStat_ && (!module_.isNull()))
sane = FALSE;
if (!sane)
{
diags << DgSqlCode(mxcmpUmInvalidCombinationOfOptions); cout << diags;
usage(argc, argv);
}
}
void Cmdline_Args::overwriteSettings() const
{
for (CollIndex x=0; x<settings_.entries(); x++) {
NAString value(settings_[x].attrValue);
ActiveSchemaDB()->getDefaults().validateAndInsert
(settings_[x].attrName.data(), value, FALSE /*don't reset*/);
}
}
void Cmdline_Args::usage(Int32 argc, char ** argv)
{
// If user typed only "arkcmp" w/no options or args, print only usage msg;
// if any opts or args, print only the bad cmdline.
if (argc > 1)
{
printCmdline(argc, argv);
NAExit(1);
}
Space localHeap;
ComDiagsArea diags(&localHeap); diags << DgSqlCode(mxcmpUsage); cout << diags;
NAExit(0);
} // Cmdline_Args::usage()
void Cmdline_Args::printArgs()
{
// cout, not cerr
// cout changed to cerr in order to satisfy th requirements for c89.
cerr << "Print command line arguments" << endl;
cerr << "application_ = " << application_ << endl;
cerr << " hasListing_ = " << hasListing_ << endl;
cerr << " moddef_ = " << moddef_ << endl;
cerr << " module_ = " << module_ << endl;
cerr << " isStat_ = " << isStat_ << endl;
cerr << "isVerbose_ = " << isVerbose_ << endl;
cerr << "ignoreErrors_ = " << ignoreErrors_ << endl;
cerr << "modulePlacement_ = " << modulePlacement_ << endl;
cerr << "moduleDir_ = " << moduleDir_.data() << endl;
// print command-line-specified control query defaults
for (CollIndex x=0; x<settings_.entries(); x++) {
cerr << settings_[x].attrName.data() << "="
<< settings_[x].attrValue.data() << endl;
}
cerr << endl;
} // end Cmdline_Args::printArgs()