blob: 06ec7bf0b078f31d017fde4685bb66c4a38ef48e [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: CmpSqlSession.cpp
* Description:
*
* Created: 6/6/2006
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "ComSmallDefs.h"
#include "CmpSqlSession.h"
#include "ObjectNames.h"
#include "ComSchemaName.h"
#include "NAUserId.h"
#include "SQLCLIdev.h"
#include "ComSqlId.h"
#include "ComRtUtils.h"
#include "ComCextdecs.h"
#define SQLPARSERGLOBALS_FLAGS
#include "SqlParserGlobals.h" // last #include
CmpSqlSession::CmpSqlSession(NAHeap * heap)
: heap_(heap),
numSessions_(0),
sessionInUse_(FALSE),
volatileSchemaInUse_(FALSE),
vsiuWasSaved_(FALSE),
savedVSIU_(FALSE),
segmentNum_(-1),
parentQid_(NULL)
{
// The initial user ID will be the default identity chosen by the
// local CLI. Call getUserInfoFromCLI() to retrieve the user ID and
// name from CLI and store copies in this instance.
//
Int32 sqlcode = getUserInfoFromCLI();
CMPASSERT(sqlcode == 0);
}
CmpSqlSession::~CmpSqlSession()
{
if (parentQid_)
{
NADELETEBASIC(parentQid_, heap_);
parentQid_ = NULL;
}
}
// Private method to retrieve user information from CLI and store a
// copy in the databaseUserID_ and databaseUserName_ members. The
// return value is a SQLCODE. When a value other than zero is
// returned, error information is written into CmpCommon::diags().
Lng32 CmpSqlSession::getUserInfoFromCLI()
{
NABoolean doDebug = FALSE;
#ifdef _DEBUG
doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE);
if (doDebug)
printf("[DBUSER:%d] BEGIN CmpSqlSession::getUserInfoFromCLI\n",
(int) getpid());
#endif
Lng32 sqlcode = 0;
Int32 localUserID = 0;
char localUserName[MAX_DBUSERNAME_LEN+1] = "";
sqlcode = SQL_EXEC_GetSessionAttr(SESSION_DATABASE_USER_ID,
&localUserID, NULL, 0, NULL);
if (sqlcode != 0)
{
SQL_EXEC_MergeDiagnostics_Internal(*CmpCommon::diags());
SQL_EXEC_ClearDiagnostics(NULL);
}
if (doDebug)
printf("[DBUSER:%d] SQL_EXEC_GetSessionAttr returned %d\n",
(int) getpid(), (int) sqlcode);
if (sqlcode >= 0)
{
sqlcode = SQL_EXEC_GetSessionAttr(SESSION_DATABASE_USER_NAME,
NULL,
localUserName,
sizeof(localUserName),
NULL);
if (sqlcode != 0)
{
SQL_EXEC_MergeDiagnostics_Internal(*CmpCommon::diags());
SQL_EXEC_ClearDiagnostics(NULL);
}
if (doDebug)
printf("[DBUSER:%d] SQL_EXEC_GetSessionAttr returned %d\n",
(int) getpid(), (int) sqlcode);
}
if (sqlcode >= 0)
{
databaseUserID_ = localUserID;
databaseUserName_ = localUserName;
// On Linux the value of externalUserName_ is always the same as
// databaseUserName_
externalUserName_ = localUserName;
if (doDebug)
printf("[DBUSER:%d] Retrieved user ID %d, name [%s]\n",
(int) getpid(), (int) localUserID, localUserName);
}
if (doDebug)
printf("[DBUSER:%d] END CmpSqlSession::getUserInfoFromCLI\n",
(int) getpid());
return sqlcode;
}
// This method is called when a message from the master executor
// arrives informing the compiler to establish a new user
// identity. The return value is a SQLCODE. When a value other than
// zero is returned, error information is found in CmpCommon::diags().
//
// The method performs the following steps
// 1. The method is a no-op if the new user ID is the same as the
// current user ID
// 2. Call CLI with the new integer user ID and username. This establishes
// the new user identity.
// 3. Call a helper method that will retrieve the current user ID and
// user name from CLI and store copies of those values in data
// members.
Lng32 CmpSqlSession::setDatabaseUser(Int32 userID, const char *userName)
{
NABoolean doDebug = FALSE;
#ifdef _DEBUG
doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE);
if (doDebug)
{
printf("[DBUSER:%d] BEGIN CmpSqlSession::setDatabaseUser\n",
(int) getpid());
printf("[DBUSER:%d] Current user ID %d, new user ID %d\n",
(int) getpid(), (int) databaseUserID_, (int) userID);
}
#endif
// 1. The method is a no-op if the new user ID is the same as the
// current user ID. This assumes that if the user ID match so
// do the usernames.
Int32 currentUserAsInt = (Int32) databaseUserID_;
if (currentUserAsInt == userID)
{
if (doDebug)
printf("[DBUSER:%d] END CmpSqlSession::setDatabaseUser\n",
(int) getpid());
return 0;
}
Lng32 sqlcode = 0;
// 2. Call CLI with the new integer user identity
sqlcode = SQL_EXEC_SetSessionAttr_Internal(SESSION_DATABASE_USER,
userID, (char *)userName);
if (sqlcode != 0)
{
SQL_EXEC_MergeDiagnostics_Internal(*CmpCommon::diags());
SQL_EXEC_ClearDiagnostics(NULL);
}
if (doDebug)
printf("[DBUSER:%d] SQL_EXEC_SetSessionAttr returned %d\n",
(int) getpid(), (int) sqlcode);
// 3. Call a helper method that will retrieve the current user ID and
// user name from CLI and store copies
if (sqlcode >= 0)
sqlcode = getUserInfoFromCLI();
if (doDebug)
printf("[DBUSER:%d] END CmpSqlSession::setDatabaseUserID\n",
(int) getpid());
return sqlcode;
}
void CmpSqlSession::setSessionId(NAString &sessionID)
{
sessionID_ = sessionID;
if (NOT sessionID_.isNull())
{
volatileSchemaName_ = COM_VOLATILE_SCHEMA_PREFIX;
volatileSchemaName_ += COM_SESSION_ID_PREFIX;
char sName[200];
Int64 cpu_l;
Int64 pin_l;
Int64 schemaNameCreateTime = 0;
Int64 sessionUniqNum;
Lng32 userNameLen = 0;
Lng32 userSessionNameLen = 0;
ComSqlId::extractSqlSessionIdAttrs
((char*)sessionID.data(),
sessionID.length(),
segmentNum_,
cpu_l,
pin_l,
schemaNameCreateTime,
sessionUniqNum,
userNameLen, NULL,
userSessionNameLen, NULL);
str_sprintf(sName, "%02d%03ld%06ld%018ld%010ld",
ComSqlId::SQ_SQL_ID_VERSION,
segmentNum_, pin_l, schemaNameCreateTime,
sessionUniqNum);
volatileSchemaName_ += sName;
volatileSchemaName_.toUpper();
// get segment name
segmentName_ = "NSK";
sessionInUse_ = TRUE;
volatileSchemaInUse_ = FALSE;
//
// it's a new session
numSessions_++;
}
else
{
sessionInUse_ = FALSE;
volatileSchemaInUse_ = FALSE;
}
}
void CmpSqlSession::setSessionUsername(NAString &userName)
{
if (NOT userName.isNull())
{
/* Prior to Seaquest M4, the string received here would be a
session ID and we would extract the user name from the session
ID. This step is no longer needed. The old code is shown here
in this comment, in case the old scheme ever needs to be
revived.
char uName[42];
Int64 uNameLen = 40;
ComSqlId::getSqlSessionIdAttr
(ComSqlId::SQLQUERYID_USERNAME,
(char*)sessionUsername.data(),
sessionUsername.length(),
uNameLen,
uName);
databaseUserName_ = uName;
databaseUserName_.strip();
*/
databaseUserName_ = userName;
databaseUserName_.strip();
short status = 1;
char ldapName[ComSqlId::MAX_LDAP_USER_NAME_LEN + 1];
if (status)
{
// On NT and Linux: the value of externalUserName_ is always the
// same as databaseUserName_
//
// On NSK: It is a maintenance id if status == 13. Otherwise we
// just revert to old behaviour and set the LDAP name to be the
// same as the database user name. Stricter error handling here
// will need to be tested more.
strcpy(ldapName, databaseUserName_.data());
}
externalUserName_ = ldapName;
externalUserName_.strip();
}
}
void CmpSqlSession::setVolatileCatalogName(NAString &volatileCatalogName,
NABoolean noSegmentAppend)
{
volatileCatalogName_ = volatileCatalogName;
if ((NOT noSegmentAppend) && (NOT segmentName_.isNull()))
{
volatileCatalogName_ += "_";
volatileCatalogName_ += segmentName_;
}
volatileCatalogName_.toUpper();
}
void CmpSqlSession::setVolatileSchemaName(NAString &volatileSchemaName)
{
volatileSchemaName_ = volatileSchemaName;
volatileSchemaName_.toUpper();
}
NABoolean CmpSqlSession::isValidVolatileSchemaName(NAString &schName)
{
if (NOT schName.isNull())
{
ComSchemaName csn(schName);
if (NOT csn.isValid())
{
// Schema name $0~SchemaName is not valid.
*CmpCommon::diags() << DgSqlCode(-8009)
<< DgSchemaName(schName);
return FALSE;
}
Lng32 len = MINOF(strlen(csn.getSchemaNamePartAsAnsiString().data()),
strlen(COM_VOLATILE_SCHEMA_PREFIX));
NAString upSch(csn.getSchemaNamePartAsAnsiString().data());
upSch.toUpper();
if ((len > 0) &&
(strncmp(upSch.data(), COM_VOLATILE_SCHEMA_PREFIX, len) == 0))
{
return TRUE;
}
}
return FALSE;
}
NABoolean CmpSqlSession::validateVolatileSchemaName(NAString &schName)
{
if (NOT schName.isNull())
{
ComSchemaName csn(schName);
if (NOT csn.isValid())
{
// Schema name $0~SchemaName is not valid.
*CmpCommon::diags() << DgSqlCode(-8009)
<< DgSchemaName(schName);
return FALSE;
}
Lng32 len = MINOF(strlen(csn.getSchemaNamePartAsAnsiString().data()),
strlen(COM_VOLATILE_SCHEMA_PREFIX));
NAString upSch(csn.getSchemaNamePartAsAnsiString().data());
upSch.toUpper();
if ((NOT Get_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME)) &&
(len > 0) &&
(strncmp(upSch.data(), COM_VOLATILE_SCHEMA_PREFIX, len) == 0))
{
*CmpCommon::diags() << DgSqlCode(-4193)
<< DgString0(COM_VOLATILE_SCHEMA_PREFIX);
return FALSE;
}
}
return TRUE;
}
NABoolean CmpSqlSession::validateVolatileQualifiedSchemaName
(QualifiedName &inName)
{
if (NOT inName.getSchemaName().isNull())
{
if (!validateVolatileSchemaName((NAString&)inName.getSchemaNameAsAnsiString()))
return FALSE;
}
return TRUE;
}
NABoolean CmpSqlSession::validateVolatileQualifiedName(QualifiedName &inName)
{
if (NOT Get_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME))
{
if (NOT inName.getCatalogName().isNull())
{
// cannot be a 3-part name
*CmpCommon::diags() << DgSqlCode(-4192);
return FALSE;
}
if (NOT inName.getSchemaName().isNull())
{
// validate that the schemaName part is the currentUserName
if (inName.getSchemaName() != externalUserName_)
{
*CmpCommon::diags() << DgSqlCode(-4191) <<
DgString0(inName.getSchemaName()) <<
DgString1(externalUserName_);
return FALSE;
}
}
}
else
{
// Volatile schema name is allowed.
// Make sure that it is a valid volatile 3 part name.
if ((NOT inName.getCatalogName().isNull()) &&
(NOT inName.getSchemaName().isNull()))
{
// move to a temp to upcase
ComSchemaName csn(inName.getSchemaName());
ULng32 len =
MINOF(strlen(csn.getSchemaNamePartAsAnsiString().data()),
strlen(COM_VOLATILE_SCHEMA_PREFIX));
NAString upSch(csn.getSchemaNamePartAsAnsiString().data());
upSch.toUpper();
if ((len < strlen(COM_VOLATILE_SCHEMA_PREFIX)) ||
(strncmp(upSch.data(), COM_VOLATILE_SCHEMA_PREFIX, len) != 0))
{
*CmpCommon::diags() << DgSqlCode(-4192);
return FALSE;
}
}
else if (NOT inName.getSchemaName().isNull())
{
// 2 part name
// validate that the schemaName part is the currentUserName
if (inName.getSchemaName() != externalUserName_)
{
*CmpCommon::diags() << DgSqlCode(-4191) <<
DgString0(inName.getSchemaName()) <<
DgString1(externalUserName_);
return FALSE;
}
}
}
return TRUE;
}
NABoolean CmpSqlSession::validateVolatileCorrName(CorrName &corrName)
{
// make sure that if schema name was specified as part of tablename,
// it is the current user name.
NABoolean isValid = FALSE;
if (NOT corrName.isVolatile())
{
//BYPASS_CHECK_FOR_VOLATILE_SCHEMA_NAME CQD was introduced as a workaround for problem seen in ALM case# 4764.
if (((corrName.isSpecialTable()) && (CmpCommon::getDefault(BYPASS_CHECK_FOR_VOLATILE_SCHEMA_NAME) == DF_ON))
||
validateVolatileQualifiedName(corrName.getQualifiedNameObj()))
{
isValid = TRUE;
}
}
else
{
isValid = TRUE;
}
return isValid;
}
NABoolean CmpSqlSession::validateVolatileName(const char * name)
{
ComObjectName volTabName(name);
NAString schemaNamePart =
volTabName.getSchemaNamePartAsAnsiString(TRUE);
schemaNamePart.toUpper();
ULng32 len =
MINOF(schemaNamePart.length(),
strlen(COM_VOLATILE_SCHEMA_PREFIX));
if ((len < strlen(COM_VOLATILE_SCHEMA_PREFIX)) ||
(strncmp(schemaNamePart.data(), COM_VOLATILE_SCHEMA_PREFIX, len) != 0))
{
return FALSE;
}
return TRUE;
}
QualifiedName * CmpSqlSession::updateVolatileQualifiedName(QualifiedName &inName)
{
QualifiedName *result = &inName;
if (volatileSchemaInUse_)
{
result = new (heap_)
QualifiedName(inName.getObjectName(),
volatileSchemaName(), volatileCatalogName(), heap_);
CMPASSERT(result);
result->setNamePosition(inName.getNamePosition());
result->setIsVolatile(TRUE);
}
return result;
}
QualifiedName * CmpSqlSession::updateVolatileQualifiedName(const NAString &inName)
{
QualifiedName *result = NULL;
if (volatileSchemaInUse_)
{
result = new (heap_)
QualifiedName(inName,
volatileSchemaName(), volatileCatalogName(), heap_);
CMPASSERT(result);
result->setIsVolatile(TRUE);
}
return result;
}
SchemaName * CmpSqlSession::updateVolatileSchemaName()
{
SchemaName *result = NULL;
result = new (heap_)
SchemaName(volatileSchemaName(), volatileCatalogName(), heap_);
CMPASSERT(result);
return result;
}
CorrName CmpSqlSession::getVolatileCorrName(CorrName &corrName)
{
NAString volTabName = corrName.getQualifiedNameObj().getObjectName();
CorrName newCorrName(volTabName, heap_,
volatileSchemaName(), volatileCatalogName(),
corrName.getCorrNameAsString());
newCorrName.setSpecialType(corrName.getSpecialType());
return newCorrName;
}
void CmpSqlSession::saveVolatileSchemaInUse()
{
if (NOT vsiuWasSaved_)
{
vsiuWasSaved_ = TRUE;
savedVSIU_ = volatileSchemaInUse_;
}
};
void CmpSqlSession::disableVolatileSchemaInUse()
{
saveVolatileSchemaInUse();
volatileSchemaInUse_ = FALSE;
// set sqlparserflags to indicate volatile schema has
// been disabled. This will be propagated to any mxcmp
// that are started by this process.
Set_SqlParser_Flags(DISABLE_VOLATILE_SCHEMA);
SQL_EXEC_SetParserFlagsForExSqlComp_Internal(DISABLE_VOLATILE_SCHEMA);
}
void CmpSqlSession::restoreVolatileSchemaInUse()
{
if (vsiuWasSaved_)
{
volatileSchemaInUse_ = savedVSIU_;
if (savedVSIU_)
{
Reset_SqlParser_Flags(DISABLE_VOLATILE_SCHEMA);
SQL_EXEC_ResetParserFlagsForExSqlComp_Internal(DISABLE_VOLATILE_SCHEMA);
}
}
vsiuWasSaved_ = FALSE;
};
NABoolean CmpSqlSession::volatileSchemaInUse()
{
return ((volatileSchemaInUse_) &&
(NOT Get_SqlParser_Flags(DISABLE_VOLATILE_SCHEMA)));
}
void CmpSqlSession::setParentQid(const char *parentQid)
{
if (parentQid)
{
Int32 len = str_len(parentQid);
if (len < ComSqlId::MIN_QUERY_ID_LEN)
abort();
if (len > ComSqlId::MAX_QUERY_ID_LEN)
abort();
if (0 != str_cmp(parentQid, COM_SESSION_ID_PREFIX, 4))
abort();
if (parentQid_ == NULL)
parentQid_ = new(heap_) char[ComSqlId::MAX_QUERY_ID_LEN+1];
strcpy(parentQid_, parentQid);
}
else if (parentQid_)
{
NADELETEBASIC(parentQid_, heap_);
parentQid_ = NULL;
}
}