blob: bc125e1d93c499a91c3ba046984b005274452c81 [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: ExtQualModuleNames.cpp
* Description: This class encapsulates the scanning, parsing, accessing of
* externally qualified module names for mxCompileUserModule.
* Created: 04/11/2003
* Language: C++
*
*****************************************************************************
*/
#include <ctype.h>
#include <iostream>
#include "ComDiags.h"
#include "DgBaseType.h"
#include "ExtQualModuleNames.h"
#include "mxCompileUserModule.h"
#include "NAString.h"
// constructor
ExtQualModuleNames::ExtQualModuleNames(char* argv[], Int32 startIndex, Int32 argc,
const char* cat, const char* sch,
const char* grp, const char* tgt,
const char* ver)
: modules_(), buffer_(), currentTokenCode_(SCANEOF), currentToken_(),
moduleCatalog_(cat), moduleSchema_(sch), moduleGroup_(grp),
moduleTableSet_(tgt), moduleVersion_(ver)
{
// make sure we have reasonable arguments
if (!argv || startIndex >= argc) {
bp_ = buffer_.end();
return;
}
for (Int32 x = startIndex; x < argc; x++) {
buffer_ += argv[x]; // collect arguments into buffer_
buffer_ += ' ';
}
// prime scanner
bp_ = buffer_.begin();
}
// destructor
ExtQualModuleNames::~ExtQualModuleNames()
{
// all data members are in-line, so their destructors are called
// automatically.
}
// return one of: ID, MODULEGROUP, MODULETABLESET, MODULEVERSION
ExtQualModuleNames::tokenType ExtQualModuleNames::checkReserved()
{
if (currentToken_ == "MODULEGROUP")
return MODULEGROUP;
if (currentToken_ == "MODULETABLESET")
return MODULETABLESET;
if (currentToken_ == "MODULEVERSION")
return MODULEVERSION;
return ID;
}
// return string form of token t (used for composing error messages)
const char* ExtQualModuleNames::tokenString(tokenType t)
{
switch (t) {
default : return "";
case LBRACE: return "{";
case RBRACE: return "}";
case COMMA : return ",";
case DOT : return ".";
case EQUAL : return "=";
case ID : return "identifier";
case MODULEGROUP : return "MODULEGROUP";
case MODULETABLESET: return "MODULETABLESET";
case MODULEVERSION : return "MODULEVERSION";
case SCANEOF : return "end-of-string";
}
}
// return next token
ExtQualModuleNames::tokenType ExtQualModuleNames::scanner()
{
currentToken_ = "";
if (atEnd()) {
return SCANEOF;
}
while (!atEnd()) {
const char cc = returnAdvanceChar();
if (isspace((unsigned char)cc)) { // For VS2003...
continue; // do nothing
}
else if (isalpha(cc)) { // regular identifier
currentToken_ += cc;
while (isalnum(currentChar()) || currentChar() == '_') {
currentToken_ += currentChar();
advanceChar();
}
// convert id to internal format (ie, uppercase it)
NAString id(currentToken_.c_str());
if (ToInternalIdentifier(id) != 0) {
*mxCUMptr << FAIL << DgSqlCode(-2215)
<< DgString0(currentToken_.c_str());
}
currentToken_ = id.data();
return checkReserved();
}
currentToken_ += cc;
switch (cc) {
case '{' :
case '}' :
case ',' :
case '.' :
case '=' :
return tokenType(cc);
case '"':
// "delimited identifier" specified by \"([^\"]|"\"\"")*\"
while (!atEnd()) {
const char c1 = returnAdvanceChar();
currentToken_ += c1;
if (c1 == '"') {
if (currentChar() == '"') {
currentToken_ += currentChar();
}
else { // end of delimited identifier
// convert delimited id to internal format
NAString id(currentToken_.c_str());
if (ToInternalIdentifier(id, FALSE, TRUE) != 0) {
*mxCUMptr << FAIL << DgSqlCode(-2209)
<< DgString0(currentToken_.c_str());
}
currentToken_ = id.data();
return ID;
}
}
}
*mxCUMptr << FAIL << DgSqlCode(-2210); // unterminated string
return ID;
default:
advanceChar();
*mxCUMptr << FAIL << DgSqlCode(-2211)
<< DgString0(currentToken_.c_str());
return SCANERROR;
}
}
return SCANEOF;
}
// return current token string (used in syntax error message)
const char* ExtQualModuleNames::currentTokenString()
{
if (currentToken_.length())
return currentToken_.c_str();
if (atEnd())
return "end-of-string";
return &(*bp_); // Return pointer to _bp location
}
// match a terminal symbol t
void ExtQualModuleNames::match(tokenType t)
{
if (nextToken() == t) { // matches t. all is OK.
currentTokenCode_ = scanner(); // get next token
}
else {
*mxCUMptr << FAIL << DgSqlCode(-2212) << DgString0(tokenString(t))
<< DgString1(currentTokenString());
}
}
void ExtQualModuleNames::parseExternallyQualifiedModuleNames()
{
// goal ::= ( <module name> [,<module name>]... )
match(LBRACE);
parseModuleNameList();
match(RBRACE);
match(SCANEOF);
}
void ExtQualModuleNames::parseModuleNameList()
{
// <module name list> ::= <module name> [,<module name>]...
parseModuleName();
while (true) {
if (nextToken() == COMMA) {
match(COMMA);
parseModuleName();
}
else {
return;
}
}
}
void ExtQualModuleNames::parseModuleName()
{
// <module name> ::= [[<catalog>.]<schema>.]<module> <qualifiers>
std::string cat, sch, mod, grp, tgt, ver;
ThreePartModuleName eqmn;
switch(nextToken()) {
case ID:
parseModule(cat, sch, mod);
parseQualifiers(grp, tgt, ver);
composeEQMN(grp, cat, sch, mod, tgt, ver, eqmn);
modules_.push_back(eqmn);
break;
default:
break;
}
}
void ExtQualModuleNames::parseModule
(std::string& cat, std::string& sch, std::string& mod)
{
// parse [[<catalog>.]<schema>.]<module>
std::string id1, id2;
if (nextToken() == ID) {
id1 = currentToken_;
match(ID);
if (nextToken() == DOT) {
match(DOT);
if (nextToken() == ID) {
id2 = currentToken_;
match(ID);
if (nextToken() == DOT) {
match(DOT);
if (nextToken() == ID) { // module is <cat>.<sch>.<mod>
cat = id1;
sch = id2;
mod = currentToken_;
match(ID);
}
else {
*mxCUMptr << FAIL << DgSqlCode(-2213)
<< DgString0(currentToken_.c_str());
}
}
else { // nextToken != DOT
sch = id1; // module is <sch>.<mod>
mod = id2;
cat = moduleCatalog_;
}
}
else {
*mxCUMptr << FAIL << DgSqlCode(-2213)
<< DgString0(currentToken_.c_str());
}
}
else { // nextToken != DOT
mod = id1; // module is just <mod>
sch = moduleSchema_;
cat = moduleCatalog_;
}
}
}
void ExtQualModuleNames::parseQualifiers
(std::string& grp, std::string& tgt, std::string& ver)
{
// parse [MODULEGROUP=[<grp>]] [MODULETABLESET=[<tgt>]]
// [MODULEVERSION=[<ver>]]
grp = moduleGroup_;
tgt = moduleTableSet_;
ver = moduleVersion_;
if (nextToken() == MODULEGROUP) {
match(MODULEGROUP);
match(EQUAL);
if (nextToken() == ID) {
grp = currentToken_;
match(ID);
}
}
if (nextToken() == MODULETABLESET) {
match(MODULETABLESET);
match(EQUAL);
if (nextToken() == ID) {
tgt = currentToken_;
match(ID);
}
}
if (nextToken() == MODULEVERSION) {
match(MODULEVERSION);
match(EQUAL);
if (nextToken() == ID) {
ver = currentToken_;
match(ID);
}
}
}
// compose externally qualified module name from its component names
void ExtQualModuleNames::composeEQMN
(std::string& grp, std::string& cat, std::string& sch,
std::string& mod, std::string& tgt, std::string& ver,
ThreePartModuleName& eqmn)
{
if (cat.length()) {
eqmn.catalog = cat;
}
if (sch.length()) {
eqmn.schema = sch;
}
if (!grp.length() && !tgt.length() && !ver.length()) {
// no group, tableset, nor version -- so no ^
eqmn.module = mod;
}
else { // has at least one of: group, tableset, version
// is mod externally qualified?
if (strchr(mod.c_str(), '^')) { // found a ^
// it's already an EQMN, so no need to qualify it
eqmn.module = mod;
}
else { // eqmn has no ^ yet, so externally qualify it
eqmn.module += grp;
eqmn.module += '^';
eqmn.module += mod;
eqmn.module += '^';
eqmn.module += tgt;
eqmn.module += '^';
eqmn.module += ver;
}
}
}
void ExtQualModuleNames::usage()
{
cerr
<< "A module name list should be" << endl
<< " (<module name>[,<module name>]...)" << endl
<< "where each <module name> can be" << endl
<< " [[<catalog>.]<schema>.]<module> [MODULEGROUP=[<group>]]" << endl
<< " [MODULETABLESET=[<target>]][MODULEVERSION=[<version>]]" << endl;
exit(EXIT_FAILURE);
}
// return true iff module is in this list
bool ExtQualModuleNames::contains(std::string &moduleName)
{
for (Int32 x=0; x<count(); x++) {
std::string name;
modules_[x].setFullyQualifiedName(name);
if (name == moduleName) {
modules_[x].found = true;
return true;
}
}
return false;
}
// process externally qualified module names
void ExtQualModuleNames::processExtQualModuleNames()
{
// scan, parse, normalize, store externally qualified module names
// into modules_
currentTokenCode_ = scanner();
parseExternallyQualifiedModuleNames();
}