예제 #1
0
short ex_tcb::handleError(ex_queue_pair *qparent, ComDiagsArea *inDiagsArea)
{
  if (qparent->up->isFull())
    return 1;
  
  // Return EOF.
  ex_queue_entry * up_entry = qparent->up->getTailEntry();
  ex_queue_entry * pentry_down = qparent->down->getHeadEntry();
  
  up_entry->upState.parentIndex = 
    pentry_down->downState.parentIndex;
  
  up_entry->upState.setMatchNo(0);
  up_entry->upState.status = ex_queue::Q_SQLERROR;
  
  ComDiagsArea *diagsArea = up_entry->getDiagsArea();
  
  if (diagsArea == NULL)
    diagsArea = 
      ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap());
  else
    diagsArea->incrRefCount (); // the setDiagsArea below will decr the ref count
  
  if (inDiagsArea)
    diagsArea->mergeAfter(*inDiagsArea);
  
  up_entry->setDiagsArea (diagsArea);
  
  // insert into parent
  qparent->up->insert();
  
  return 0;
}
예제 #2
0
SP_HELPER_STATUS CmpSPExtractFunc_ (
                                    Lng32 fieldNo, 
                                    SP_ROW_DATA rowData, 
                                    Lng32 fieldLen, 
                                    void* fieldData,
                                    Lng32 casting )
{
  CmpSPExecDataItemInput* inPtr = (CmpSPExecDataItemInput*)rowData;
  ULng32 tempNum = (ULng32)fieldNo;
  ULng32 tempLen = (ULng32)fieldLen;
  ComDiagsArea* diags = inPtr->SPFuncsDiags();
  if ( inPtr->extract(tempNum,(char*)fieldData,tempLen, 
    ((casting==1) ? TRUE : FALSE), diags) < 0 ||
    diags->getNumber() )
  {
    // TODO, convert the errors in diags into error code.
    diags->clear(); // to be used for next CmpSPExtractFunc_
    return SP_ERROR_EXTRACT_DATA;
  }
  // test code for assert, check for arkcmp/SPUtil.cpp SP_ERROR_*
  // for detail description.
  //#define ASTRING "TestCMPASSERTEXE"
  //assert( strncmp((char*)fieldData, ASTRING, strlen(ASTRING) != 0 ) ) ;

  return SP_NO_ERROR;
}
Int32 sqlci_parser_handle_error(SqlciNode **node, Lng32 retval)
{
  NABoolean syntaxError_ = sqlci_DA.contains(-SQLCI_SYNTAX_ERROR);
  
  if (retval && syntaxError_)
    {	
      if (SqlciEnvGlobal->isReportWriterMode())
	{
	  SqlciParseTree = (SqlciNode *)new SqlciRWQueryCmd(SqlciParse_OriginalStr,
			(Lng32)strlen(SqlciParse_OriginalStr));
	  assert(SqlciParseTree->isSqlciNode());
	  *node = SqlciParseTree;	
	  sqlci_DA.clear(); // clear the diagonistics
	  return 0;
	}
      else if (SqlciEnvGlobal->isMXCSMode())
      {
        SqlciParseTree = (SqlciNode *)new SqlciCSQueryCmd(SqlciParse_OriginalStr,
                               (Lng32)strlen(SqlciParse_OriginalStr));
	  assert(SqlciParseTree->isSqlciNode());
	  *node = SqlciParseTree;	
	  sqlci_DA.clear(); // clear the diagonistics
	  return 0;
      }
      else
	return retval;
    }
  else
    return retval;
  
}
예제 #4
0
// sqlci run with input coming in from an infile specified at command line
void SqlciEnv::run(char * in_filename, char * input_string)
{
  if ((! in_filename) && (input_string))
    {
      runWithInputString(input_string);
      return;
    }
  interactive_session = 0;		// overwrite value from ctor!
  // This function is called during the initialization phase of MXCI
  // (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
  // the querry being executed is invoke during MXCI's initialization phase and
  // that any errors will be fatal. Should an error occur,  exit MXCI.
  SqlciEnv_prologue_to_run(this);

   SqlCmd::executeQuery("SET SESSION DEFAULT SQL_SESSION 'BEGIN';", this);
  Int32 retval = 0;
  SqlciNode * sqlci_node = 0;

  // input is from a file given at command line (SQLCI -i<filename>).
  // Create an "OBEY filename" command and process it.
  char * command = new char[10 + strlen(in_filename)];
  strcpy(command, "OBEY ");
  strcat(command, in_filename);
  strcat(command, ";");
  sqlci_parser(command, command, &sqlci_node,this);
  delete [] command;
  void (*intHandler_addr) (Int32);
  intHandler_addr = interruptHandler;
      if (sqlci_node)
      {
        retval = sqlci_node->process(this);
        delete sqlci_node;
        sqlci_node = NULL;
        displayDiagnostics();
        sqlci_DA.clear(); // Clear the DiagnosticsArea for the next command...
      }

      if (!retval) // EXIT not seen in the obey file
      {
        // create an EXIT command
        char command[10];
        strcpy(command, "exit;");
        get_logfile()->WriteAll(">>exit;");
        sqlci_parser(command, command, &sqlci_node,this);
        if (sqlci_node)
	{
	  retval = sqlci_node->process(this);
	  delete sqlci_node;
          sqlci_node = NULL;
	  displayDiagnostics();
	  sqlci_DA.clear();
	}
      }
   DeleteCriticalSection(&g_CriticalSection);
   DeleteCriticalSection(&g_InterruptCriticalSection);

  cleanupSockets();
}  // run (in_filename)
예제 #5
0
// LCOV_EXCL_START
void ExSequenceTcb::updateDiagsArea(  ExeErrorCode rc_)
{                   
    ComDiagsArea *da = workAtp_->getDiagsArea();
    if(!da) 
    {
      da = ComDiagsArea::allocate(heap_);
      workAtp_->setDiagsArea(da);
    }
    if (!da->contains((Lng32) -rc_))
    {
      *da << DgSqlCode(-rc_);
    }
}
예제 #6
0
ComDiagsArea *ExRaiseSqlError(CollHeap* heap, ex_queue_entry* req,
			      ExeErrorCode err, 
			      Lng32 * intParam1,
			      char * stringParam1,
			      ComCondition** newCond)
{
  ComDiagsArea* da = req->getDiagsArea();
  if (da == NULL)
    da = ComDiagsArea::allocate(heap);
  else
    da = da->copy();
  
  return ExRaiseSqlError(heap, &da, (ExeErrorCode)(-err), newCond, intParam1, NULL, NULL, stringParam1);
}
예제 #7
0
void interruptHandler (Int32 signalType)
{
   void (*intHandler_addr) (Int32);
   intHandler_addr = interruptHandler;
   Lng32 retcode = 0; // for return of success or failure from handleBreak methods in MACL and RW.

   UInt32 recoverNeeded = 0;

   signal(SIGINT, intHandler_addr);  // arm the signal for break.
   // This is for the Break key abend problem in Outside View for NSK.  Instead of SIGINT,
   // SIGQUIT is being sent by the TELSRV people to OSS.  We catch it right here.


   if (TryEnterCriticalSection(&g_CriticalSection))
     {
	   Lng32 eCode = SQL_EXEC_Cancel(0);
		if (eCode ==0) {

			LeaveCriticalSection(&g_CriticalSection);

		}
		else { // retry
			switch (-eCode) {
			case CLI_CANCEL_REJECTED:
				{
				  SqlciEnv s;
				  s.displayDiagnostics();
				  sqlci_DA.clear();
				  LeaveCriticalSection(&g_CriticalSection);

				}
				break;
			default:
				{
				 sqlci_DA << DgSqlCode(SQLCI_BREAK_ERROR, DgSqlCode::WARNING_);
				 SqlciEnv s;
				 s.displayDiagnostics();
				 sqlci_DA.clear();
				 LeaveCriticalSection(&g_CriticalSection);
				}
				break;
			}
		}

     }

}
void ExFastExtractTcb::updateWorkATPDiagsArea(ex_queue_entry * centry)
{
    if (centry->getDiagsArea())
    {
      if (workAtp_->getDiagsArea())
      {
        workAtp_->getDiagsArea()->mergeAfter(*centry->getDiagsArea());
      }
      else
      {
        ComDiagsArea * da = centry->getDiagsArea();
        workAtp_->setDiagsArea(da);
        da->incrRefCount();
        centry->setDiagsArea(0);
      }
    }
}
예제 #9
0
void ExSequenceTcb::updateDiagsArea(ex_queue_entry * centry)
{
    if (centry->getDiagsArea()) 
    {
      if (workAtp_->getDiagsArea())
      {     
        // LCOV_EXCL_START
        workAtp_->getDiagsArea()->mergeAfter(*centry->getDiagsArea());
        // LCOV_EXCL_STOP
      }
      else
      {
        ComDiagsArea * da = centry->getDiagsArea();
        workAtp_->setDiagsArea(da);
        da->incrRefCount();
        centry->setDiagsArea(0);
      }
    }
}
예제 #10
0
ComDiagsArea *ExExeUtilLongRunningTcb::getDiagAreaFromUpQueueTail()
{
  ex_queue_entry * up_entry = qparent_.up->getTailEntry();
  ComDiagsArea *diagsArea = up_entry->getDiagsArea();

  if (diagsArea == NULL)
     diagsArea = ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap());
  else
    diagsArea->incrRefCount (); // setDiagsArea call below will decr ref count

  // this is the side-effect of this function. Merge in this object's
  // diagsarea.
  if (getDiagsArea())
    diagsArea->mergeAfter(*getDiagsArea());

  up_entry->setDiagsArea (diagsArea);

  return diagsArea;
}
예제 #11
0
SP_HELPER_STATUS CmpSPFormatFunc_ (Lng32 fieldNo,
                                   SP_ROW_DATA rowData, 
                                   Lng32 fieldLen, 
                                   void* fieldData,
                                   Lng32 casting)
{
  CmpSPExecDataItemReply* replyPtr = (CmpSPExecDataItemReply*)rowData;
#pragma nowarn(262)   // warning elimination 
  ULng32 tempNum = (ULng32)fieldNo;
  ULng32 tempLen = (ULng32)fieldLen;
  ComDiagsArea* diags = replyPtr->SPFuncsDiags();
  if ( replyPtr->moveOutput(fieldNo,(char*)fieldData,tempLen, 
    ((casting==1) ? TRUE : FALSE), diags) < 0 ||
    diags->getNumber() )
  {
    diags->clear(); // to be used for next CmpSPFormatFunc_
    return SP_ERROR_FORMAT_DATA;
  }
  else
    return SP_NO_ERROR;
}
예제 #12
0
ExProbeCacheTcb::MoveStatus 
ExProbeCacheTcb::moveReplyToCache(ex_queue_entry &reply, 
                                             ExPCE &pcEntry)
{
  if (moveInnerExpr())
    {
      ex_assert(!pcEntry.innerRowTupp_.isAllocated(),
                "reusing an allocated innerRowTupp");

      if (pool_->getFreeTuple(pcEntry.innerRowTupp_))
        return MOVE_BLOCKED;

      workAtp_->getTupp(probeCacheTdb().innerRowDataIdx_) = 
            pcEntry.innerRowTupp_;

      // Evaluate the move expression on the reply.
      ex_expr::exp_return_type innerMoveRtn = 
        moveInnerExpr()->eval(reply.getAtp(),workAtp_);
      
      if (innerMoveRtn == ex_expr::EXPR_ERROR)
        return MOVE_ERROR;
    }
  else
    {
      ex_assert(pcEntry.innerRowTupp_.isAllocated() == FALSE, 
               "Incorrectly initialized inneRowTupp_");
    }

  // Initialize ExPCE members
  pcEntry.upstateStatus_ = ex_queue::Q_OK_MMORE;
  
  ComDiagsArea *da = reply.getAtp()->getDiagsArea();
  if (da)
    {
      pcEntry.diagsArea_ =  da;
      da->incrRefCount();
    }

return MOVE_OK;
}
예제 #13
0
short ex_tcb::handleDone(ex_queue_pair *qparent, ComDiagsArea *inDiagsArea)
{
  if (qparent->up->isFull())
    return 1;
  
  // Return EOF.
  ex_queue_entry * up_entry = qparent->up->getTailEntry();
  ex_queue_entry * pentry_down = qparent->down->getHeadEntry();
  
  if (inDiagsArea && inDiagsArea->getNumber(DgSqlCode::WARNING_) > 0)
    {
      ComDiagsArea *diagsArea = up_entry->getDiagsArea();
      
      if (diagsArea == NULL)
	diagsArea = 
	  ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap());
      else
	diagsArea->incrRefCount (); // the setDiagsArea below will decr the ref count
      
      if (inDiagsArea)
	diagsArea->mergeAfter(*inDiagsArea);
      
      up_entry->setDiagsArea (diagsArea);
    }

  up_entry->upState.parentIndex = 
    pentry_down->downState.parentIndex;
  
  up_entry->upState.setMatchNo(0);
  up_entry->upState.status = ex_queue::Q_NO_DATA;
  
  // insert into parent
  qparent->up->insert();
  
  //	    pstate.matches_ = 0;
  qparent->down->removeHead();
  
  return 0;
}
예제 #14
0
Int32 sqlci_parser(char *instr, char *origstr, SqlciNode ** node, SqlciEnv *sqlci_env)
{
  Lng32 prevDiags = sqlci_DA.getNumber();	// capture this before parsing

  // replace any user defined pattern in the query
  char * newstr = origstr;
  newstr = SqlCmd::replacePattern(sqlci_env, origstr);  

  Int32 retval = sqlci_parser_subproc(instr, newstr, node, sqlci_env);
  
  // There's still some weird error in the Sqlci Lexer
  // ("OBEY F(S);FC 1;" and "OBEY F;!O;" fail -- bug in the <FNAME> state?).
  // Here we *KLUDGE* around the problem, by retrying the parse once only.
  
  if (retval)
    {
      sqlci_parser_syntax_error_cleanup(NULL, sqlci_env);
      if (!prevDiags && retval > 0)		// NOT the -99 from above!
	{
	  sqlci_DA.clear();
	  retval = sqlci_parser_subproc(instr, newstr, node, sqlci_env);
	  if (retval)
	    sqlci_parser_syntax_error_cleanup(NULL, sqlci_env);
	}
    }
  
  if (retval > 0)
    {
      SqlciParse_OriginalStr = origstr;
      retval = sqlci_parser_handle_error(node, retval);
    }

  if (newstr != origstr)
    delete [] newstr;

  return retval;
  
}
예제 #15
0
short FixCommand::process(SqlciEnv * sqlci_env)
{
  Int32 retval = 0;

  if (sqlci_env->isOleServer())
  {
	SqlciError (SQLCI_CMD_NOT_SUPPORTED,
				(ErrorParam *) 0 );
	return 0;
  }

  // ignore if FC is in an obey file, or stdin redirected from a file
  // (should we display an informative error message?)
  if (!sqlci_env->isInteractiveNow())
#pragma nowarn(1506)   // warning elimination 
    return retval;
#pragma warn(1506)  // warning elimination 

  InputStmt *input_stmt = 0, *stmt = 0;

  // Don't add the FC cmd to the sqlci stmts list. 
  sqlci_env->getSqlciStmts()->remove();

  if (cmd != 0) // Character string was provided...
    { 
      input_stmt = sqlci_env->getSqlciStmts()->get(cmd);
    }
  else
    {
      if (!cmd_num)
	input_stmt = sqlci_env->getSqlciStmts()->get();
      else
	{
	  if (neg_num) cmd_num = (sqlci_env->getSqlciStmts()->last_stmt()  
				  - cmd_num) + 1;
	  
	  input_stmt = sqlci_env->getSqlciStmts()->get(cmd_num);
	}
    }

  if (input_stmt)
    {
      enum { DUNNO, YES, NO };
      Int32 is_single_stmt = DUNNO;
      InputStmt * fc_input_stmt = new InputStmt(sqlci_env);
      *fc_input_stmt = input_stmt;

      // Prompt user to fix the input stmt.
      // Fix() value is 0 if we are to execute (and log and history) new stmt,
      // -20 if user "aborted" the FC via an EOF or "//" at the prompt
      // (we must emulate this behavior at the -20 section later on!)
      //
      if (fc_input_stmt->fix() != -20)
	{
	  if (!fc_input_stmt->isEmpty())
	    {
	      // Clear any syntax errors thrown by InputStmt::fix();
	      // we'll get to 'em one at a time in this loop
	      sqlci_DA.clear();

	      // Looping, process one or more commands ("a;b;c;")
	      // on the FC input line.
	      char * packedStr = fc_input_stmt->getPackedString();
	      do
		{
		  size_t quotePos;		// unterminated quote seen?
		  char packedEndC = '\0';
		  char * packedEnd = fc_input_stmt->findEnd(packedStr, quotePos);
		  if (!quotePos)
		    {
		      // No unterminated quote

		      if (is_single_stmt == DUNNO)
			is_single_stmt = 
			  (!packedEnd || fc_input_stmt->isEmpty(packedEnd)) ?
			  YES : NO;
			
		      if (packedEnd)		// semicolon seen
			{
			  packedEndC = *packedEnd;
			  *packedEnd = '\0';
			  if (is_single_stmt == YES && packedEndC)
			    is_single_stmt = NO;
			}

		      if (!fc_input_stmt->isEmpty(packedStr))
			{
			  if (is_single_stmt == YES)
			    stmt = fc_input_stmt;
			  else
			    stmt = new InputStmt(fc_input_stmt, packedStr);

			  Int32 read_error = 0;

			  // Unterminated stmt (no ";" seen),
			  // so prompt for the rest of it.
			  // If user enters EOF in the appended lines,
			  // then log it, but don't history it or execute it.
			  if (!packedEnd)
			    {
			      read_error = stmt->fix(-1/*append_only*/);
	      		      packedStr = stmt->getPackedString();
			    }

			  stmt->logStmt();
			  if (read_error != -20)       // see "abort" note above
			    sqlci_env->getSqlciStmts()->add(stmt);

			  if (!read_error)
			    {
			      SqlciNode * sqlci_node = 0;
			      sqlci_parser(packedStr, packedStr, &sqlci_node, sqlci_env);
			      if (sqlci_node)
				{
				  retval = sqlci_node->process(sqlci_env);
				  delete sqlci_node;
				}
			    }

			  sqlci_env->displayDiagnostics();
			  sqlci_DA.clear();
			  if (retval == -1)		// EXIT command
			    break;
			}

		      if (packedEnd)
			{
			  *packedEnd = packedEndC;
			  packedStr = packedEnd;
			}
		      else
			break;		// terminate the unterminated stmt
		    }
		  else
		    {
		      // If unterminated quote, log it and history it and
		      // display error message and exit the loop;
		      // if just trailing blanks, it's no error, exit the loop.
		      if (!fc_input_stmt->isEmpty(packedStr))
			{
			  if (is_single_stmt == DUNNO)
			    {
			      is_single_stmt = YES;
			      stmt = fc_input_stmt;
			    }
			  else
			    stmt = new InputStmt(fc_input_stmt, packedStr);
			  stmt->logStmt();
			  sqlci_env->getSqlciStmts()->add(stmt);
			  fc_input_stmt->syntaxErrorOnMissingQuote(packedStr);
			}
		      break;
		    }
		}
	      while (*packedStr);
	    }
	}
      if (is_single_stmt != YES)
	delete fc_input_stmt;
    }
  else
    {
      SqlciError(SQLCI_NO_STMT_MATCH, (ErrorParam *) 0);
    }

#pragma nowarn(1506)   // warning elimination 
  return retval;
#pragma warn(1506)  // warning elimination 
} // end FixCommand::process
예제 #16
0
short Shape::processNextStmt(SqlciEnv * sqlci_env, FILE * fStream)
{
  short retcode = 0;

  enum ShapeState 
   {
     PROCESS_STMT, DONE
   };

  Int32 done = 0;
  Int32 ignore_toggle = 0;
  ShapeState state;
  InputStmt * input_stmt;
  SqlciNode * sqlci_node = NULL;

  state = PROCESS_STMT;

  while (!done)
    {
      input_stmt = new InputStmt(sqlci_env);
      Int32 read_error = 0;
      if (state != DONE)
	{
	  read_error = input_stmt->readStmt(fStream, TRUE);
	  
	  if (feof(fStream) || read_error == -99)
	    {
	      if (!input_stmt->isEmpty() && read_error != -4)
		{
		  // Unterminated statement in obey file.
		  // Make the parser emit an error message.
		  input_stmt->display((UInt16)0, TRUE);
		  input_stmt->logStmt(TRUE);
		  input_stmt->syntaxErrorOnEof();
		}
	      state = DONE;
	    } // feof or error (=-99)
	}
      
      // if there is an eof directly after a statement
      // that is terminated with a semi-colon, process the
      // statement
      if (read_error == -4) state = PROCESS_STMT;
      
      switch (state)
	{
	case PROCESS_STMT:
	  {
	    Int32 ignore_stmt = input_stmt->isIgnoreStmt();
	    if (ignore_stmt)
	      ignore_toggle = ~ignore_toggle;
	    
	    if (ignore_stmt || ignore_toggle || input_stmt->ignoreJustThis())
	      {
		// ignore until stmt following the untoggling ?ignore
		sqlci_DA.clear();
	      }
	    else
	      {
		if (!read_error || read_error == -4)
		  {
		    sqlci_parser(input_stmt->getPackedString(),
				 input_stmt->getPackedString(),
				 &sqlci_node,sqlci_env);
		    if ((sqlci_node) &&
			(sqlci_node->getType() == SqlciNode::SQL_CMD_TYPE))
		      {
			delete sqlci_node;

			SqlCmd sqlCmd(SqlCmd::DML_TYPE, NULL);
			
			short retcode = sqlCmd.showShape(sqlci_env, 
							 input_stmt->getPackedString());
			if (retcode)
			{
			  delete input_stmt;
			  return retcode;
			}
		      }

		    input_stmt->display((UInt16)0, TRUE);
		    input_stmt->logStmt(TRUE);
		  }
		
		sqlci_env->displayDiagnostics() ;
		
		// Clear the DiagnosticsArea for the next command...
		sqlci_DA.clear();
		    
		// if an EXIT statement was seen, then a -1 will be returned
		// from process. We are done in that case.
		if (retcode == -1)
		  state = DONE;
	      }
	  }
	break;
	
	case DONE:
	  {
	    done = -1;
  	  }
	break;
	
	default:
	  {
	  }
	break;
	
	} // switch on state
      
      delete input_stmt;
      
    } // while not done

  return 0;
}
예제 #17
0
ComDiagsArea *ExAddCondition(CollHeap* heap, ComDiagsArea** diagsArea,
			     Lng32 err, ComCondition** newCond,
			     Lng32 * intParam1,
			     Lng32 * intParam2,
			     Lng32 * intParam3,
			     const char * stringParam1,
			     const char * stringParam2,
			     const char * stringParam3)
{
  //
  // This version of ExRaiseSqlError is used by the expressions code.  In
  // addition to having slightly different parameters, it differs from the
  // above version in that it puts an error condition in the supplied
  // ComDiagsArea rather than in a copy.
  //
  // If the caller didn't pass in the address of a pointer to the
  // ComDiagsArea, there's no point in creating an error condition since the
  // caller won't receive it.  Normally this should never happen, but right
  // now it may occur until all the error processing code is in place.
  //
  if (diagsArea == NULL)
    return NULL;
  //
  // The caller did pass in the address of a pointer to the ComDiagsArea.  If
  // the pointer is NULL, we need to allocate the ComDiagsArea and put its
  // address in the pointer.  Otherwise, we will put the error condition in
  // the ComDiagsArea that was supplied.
  //
  if (*diagsArea == NULL) {
    //
    // If the heap is NULL, we can't allocate the ComDiagsArea.  This should
    // never happen.
    //
    if (heap == NULL)
      return NULL;
    *diagsArea = ComDiagsArea::allocate(heap);
  }

  ComDiagsArea *da = *diagsArea;
  ComCondition *cond = da->makeNewCondition();
  cond->setSQLCODE(err);

  if (intParam1)
    cond->setOptionalInteger(0, *intParam1);
  if (intParam2)
    cond->setOptionalInteger(1, *intParam2);
  if (intParam3)
    cond->setOptionalInteger(2, *intParam3);
  if (stringParam1)
    cond->setOptionalString(0, stringParam1);
  if (stringParam2)
    cond->setOptionalString(1, stringParam2);
  if (stringParam3)
    cond->setOptionalString(2, stringParam3);

  da->acceptNewCondition();

  if (newCond) 
    *newCond = cond;

  return *diagsArea;
}
// Insert a single entry into the up queue and optionally
// remove the head of the down queue
//
// Right now this function does not handle data rows, only error
// and end-of-data. It could possibly be extended to handle a data
// row. I have not looked at that closely enough yet.
//
void ExFastExtractTcb::insertUpQueueEntry(ex_queue::up_status status,
                                  ComDiagsArea *diags,
                                  NABoolean popDownQueue)
{

  ex_queue_entry *upEntry = qParent_.up->getTailEntry();
  ex_queue_entry *downEntry = qParent_.down->getHeadEntry();
  ExFastExtractPrivateState &privateState =
    *((ExFastExtractPrivateState *) downEntry->pstate);

  // Initialize the up queue entry. 
  //
  // copyAtp() will copy all tuple pointers and the diags area from
  // the down queue entry to the up queue entry.
  //
  // When we return Q_NO_DATA if the match count is > 0:
  // * assume down queue diags were returned with the Q_OK_MMORE entries
  // * release down queue diags before copyAtp()
  //
  if (status == ex_queue::Q_NO_DATA && privateState.matchCount_ > 0)
  {
    downEntry->setDiagsArea(NULL);
    upEntry->copyAtp(downEntry);
  }
  else
  {
    upEntry->copyAtp(downEntry);
    downEntry->setDiagsArea(NULL);
  }

  upEntry->upState.status = status;
  upEntry->upState.parentIndex = downEntry->downState.parentIndex;
  upEntry->upState.downIndex = qParent_.down->getHeadIndex();
  upEntry->upState.setMatchNo(privateState.matchCount_);
  
  // Move any diags to the up queue entry
  if (diags != NULL)
  {
    ComDiagsArea *atpDiags = upEntry->getDiagsArea();
    if (atpDiags == NULL)
    {
      // setDiagsArea() does not increment the reference count
      upEntry->setDiagsArea(diags);
      diags->incrRefCount();
    }
    else
    {
      atpDiags->mergeAfter(*diags);
    }
  }
  
  // Insert into up queue
  qParent_.up->insert();
 
  // Optionally remove the head of the down queue
  if (popDownQueue)
  {
    privateState.init();
    qParent_.down->removeHead();
  }
}
예제 #19
0
short ExExeUtilPopulateInMemStatsTcb::work()
{
  //  short rc = 0;
  Lng32 cliRC = 0;

  // if no parent request, return
  if (qparent_.down->isEmpty())
    return WORK_OK;
  
  // if no room in up queue, won't be able to return data/status.
  // Come back later.
  if (qparent_.up->isFull())
    return WORK_OK;
  
  ex_queue_entry * pentry_down = qparent_.down->getHeadEntry();
  ExExeUtilPrivateState & pstate =
    *((ExExeUtilPrivateState*) pentry_down->pstate);

  // Get the globals stucture of the master executor.
  ExExeStmtGlobals *exeGlob = getGlobals()->castToExExeStmtGlobals();
  ExMasterStmtGlobals *masterGlob = exeGlob->castToExMasterStmtGlobals();
  ContextCli * currContext = masterGlob->getStatement()->getContext();

  while (1)
    {
      switch (step_)
	{
	case INITIAL_:
	  {
	    if (getDiagsArea())
	      {
		getDiagsArea()->clear();
		getDiagsArea()->deAllocate();
	      }
	    
	    setDiagsArea(ComDiagsArea::allocate(getHeap()));

	    step_ = PROLOGUE_;
	  }
	break;

	case PROLOGUE_:
	  {
	    if (disableCQS())
	      {
		step_ = ERROR_;
		break;
	      }

	    if (setSchemaVersion(pimsTdb().sourceTableCatName_))
	      {
		step_ = ERROR_;
		break;
	      }

	    // set sqlparserflags to allow use of volatile schema in queries.
	    masterGlob->getStatement()->getContext()->
	      setSqlParserFlags(0x10000);//ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME

	    step_ = DELETE_STATS_;
	  }
	break;

	case DELETE_STATS_:
	  {
	    Int32 qry_array_size = sizeof(deleteStatsQuery) 
	      / sizeof(QueryString);
	    
	    const QueryString * queryString = deleteStatsQuery;;
	    
	    char * gluedQuery;
	    Lng32 gluedQuerySize;
	    glueQueryFragments(qry_array_size, queryString,
			       gluedQuery, gluedQuerySize);
	    
	    Lng32 extraSpace = 
	      ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualTableName */
	      + 20 /* UID */
	      + 200 /* overhead */;

	    char * query = new(getHeap()) char[gluedQuerySize + extraSpace];
	    str_sprintf(query, gluedQuery, 
			(char*)pimsTdb().inMemHistogramsTableName_,
			pimsTdb().uid_);
	    
	    cliRC = 
	      cliInterface()->executeImmediate(query);
	    
	    if (cliRC >= 0)
	      {
		str_sprintf(query, gluedQuery, 
			    (char*)pimsTdb().inMemHistintsTableName_,
			    pimsTdb().uid_);
		
		cliRC = 
		  cliInterface()->executeImmediate(query);
	      }

	    // Delete new'd string
	    NADELETEBASIC(gluedQuery, getHeap());
	    gluedQuery = NULL;
	    
	    NADELETEBASIC(query, getHeap());
	    query = NULL;
	    
	    if (cliRC < 0)
	      {
                cliInterface()->allocAndRetrieveSQLDiagnostics(diagsArea_);
		step_ = ERROR_;
	      }
	    else
	      step_ = POPULATE_HISTOGRAMS_STATS_;
	  }
	break;

	case POPULATE_HISTOGRAMS_STATS_:
	  {
	    Int32 qry_array_size = sizeof(populateHistogramsStatsQuery) 
	      / sizeof(QueryString);
	    
	    const QueryString * queryString = populateHistogramsStatsQuery;;
	    
	    char * gluedQuery;
	    Lng32 gluedQuerySize;
	    glueQueryFragments(qry_array_size, queryString,
			       gluedQuery, gluedQuerySize);
	    
	    Lng32 extraSpace =
	        ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualInMemHistTableName */
	      + 20 /* UID */
	      + ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualSourceHistTableName */
	      + 2 * 10 /*segment name*/
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/
	      + 10  /*version*/ 
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*sch name*/
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*obj name*/
	      + 200 /* overhead */;

	    char * query = new(getHeap()) char[gluedQuerySize + extraSpace];
	    
	    str_sprintf(query, gluedQuery, 
			(char*)pimsTdb().inMemHistogramsTableName_,
			pimsTdb().uid_,
			(char*)pimsTdb().sourceHistogramsTableName_,
			(char*)pimsTdb().sourceTableCatName_,
			(char*)pimsTdb().sourceTableCatName_,
			(char*)pimsTdb().sourceTableSchName_,
			(char*)pimsTdb().sourceTableObjName_
			);
	    
	    cliRC = 
	      cliInterface()->executeImmediate(query);
	    
	    // Delete new'd string
	    NADELETEBASIC(gluedQuery, getHeap());
	    gluedQuery = NULL;
	    
	    NADELETEBASIC(query, getHeap());
	    query = NULL;
	    
	    if (cliRC < 0)
	      {
                cliInterface()->allocAndRetrieveSQLDiagnostics(diagsArea_);
		step_ = ERROR_;
	      }
	    else
	      step_ = POPULATE_HISTINTS_STATS_;
	  }
	break;
	  
	case POPULATE_HISTINTS_STATS_:
	  {
	    Int32 qry_array_size = sizeof(populateHistintsStatsQuery) 
	      / sizeof(QueryString);
	    
	    const QueryString * queryString = populateHistintsStatsQuery;;
	    
	    char * gluedQuery;
	    Lng32 gluedQuerySize;
	    glueQueryFragments(qry_array_size, queryString,
			       gluedQuery, gluedQuerySize);
	    
	    Lng32 extraSpace =
	        ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualInMemHistTableName */
	      + 20 /* UID */
	      + ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualSourceHistTableName */
	      + 2 * 10 /*segment name*/
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/
	      + 10  /*version*/ 
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*sch name*/
	      + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*obj name*/
	      + 200 /* overhead */;

	    char * query = new(getHeap()) char[gluedQuerySize + extraSpace];
	    
	    str_sprintf(query, gluedQuery, 
			(char*)pimsTdb().inMemHistintsTableName_,
			pimsTdb().uid_,
			(char*)pimsTdb().sourceHistintsTableName_,
			(char*)pimsTdb().sourceTableCatName_,
			(char*)pimsTdb().sourceTableCatName_,
			(char*)pimsTdb().sourceTableSchName_,
			(char*)pimsTdb().sourceTableObjName_
			);
	    
	    cliRC = 
	      cliInterface()->executeImmediate(query);
	    
	    // Delete new'd string
	    NADELETEBASIC(gluedQuery, getHeap());
	    gluedQuery = NULL;
	    
	    NADELETEBASIC(query, getHeap());
	    query = NULL;
	    
	    if (cliRC < 0)
	      {
                cliInterface()->allocAndRetrieveSQLDiagnostics(diagsArea_);
		step_ = ERROR_;
	      }
	    else
	      step_ = EPILOGUE_;
	  }
	break;

	case EPILOGUE_:
	case EPILOGUE_AND_ERROR_RETURN_:
	  {
	    // reset sqlparserflags
	    masterGlob->getStatement()->getContext()->
	      resetSqlParserFlags(0x10000);//ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME

	    restoreCQS();

	    if (step_ == EPILOGUE_AND_ERROR_RETURN_)
	      step_ = ERROR_RETURN_;
	    else
	      step_ = DONE_;
	  }
	  break;

	case ERROR_:
	  {
	    step_ = EPILOGUE_AND_ERROR_RETURN_;
	  }
	  break;

	case ERROR_RETURN_:
	  {
	    if (qparent_.up->isFull())
	      return WORK_OK;

	    // Return EOF.
	    ex_queue_entry * up_entry = qparent_.up->getTailEntry();
	    
	    up_entry->upState.parentIndex = 
	      pentry_down->downState.parentIndex;
	    
	    up_entry->upState.setMatchNo(0);
	    up_entry->upState.status = ex_queue::Q_SQLERROR;

	    ComDiagsArea *diagsArea = up_entry->getDiagsArea();
	    
	    if (diagsArea == NULL)
	      diagsArea = 
		ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap());
	    
	    if (getDiagsArea())
	      diagsArea->mergeAfter(*getDiagsArea());
	    
	    up_entry->setDiagsArea (diagsArea);
	    
	    // insert into parent
	    qparent_.up->insert();
	    
	    step_ = DONE_;
	  }
	  break;

	case DONE_:
	  {
	    if (qparent_.up->isFull())
	      return WORK_OK;
	    
	    // Return EOF.
	    ex_queue_entry * up_entry = qparent_.up->getTailEntry();
	    
	    up_entry->upState.parentIndex = 
	      pentry_down->downState.parentIndex;
	    
	    up_entry->upState.setMatchNo(0);
	    up_entry->upState.status = ex_queue::Q_NO_DATA;
	    
	    // insert into parent
	    qparent_.up->insert();
	    
	    qparent_.down->removeHead();
	    
	    step_ = INITIAL_;
	    return WORK_OK;
	  }
	
	break;
	
	default:
	  break;

	}

    }

  return 0;
}
예제 #20
0
// work - doit...
//
//
short ExSequenceTcb::work()
{
  // If there are no parent requests on the queue, then there cannot
  // be anything to do here.
  //
  if (qparent_.down->isEmpty())
    return WORK_OK;

  ex_queue_entry * pentry_down;
  ExSequencePrivateState * pstate;
  ex_queue::down_request request;

  // Take any new parent requests and pass them on to the child as long
  // as the child's queue is not full. processedInputs_ maintains the 
  // Queue index of the last request that was passed on.
  // 
  for(queue_index tail = qparent_.down->getTailIndex(); 
      (processedInputs_ != tail) && (!qchild_.down->isFull());
      processedInputs_++ )
    {
      pentry_down = qparent_.down->getQueueEntry(processedInputs_);
      pstate = (ExSequencePrivateState*) pentry_down->pstate;
      request = pentry_down->downState.request;

      // If the request has already been cancelled don't pass it to the
      // child. Instead, just mark the request as done. This will trigger
      // a EOD reply when this request gets worked on.
      //
      if (request == ex_queue::GET_NOMORE)
        {
          // LCOV_EXCL_START
          pstate->step_ = ExSeq_DONE;
          // LCOV_EXCL_STOP
        }
      else
        {
          pstate->step_ = ExSeq_WORKING_READ;

          // Pass the request to the child
          //
          ex_queue_entry * centry = qchild_.down->getTailEntry();
          centry->downState.request = ex_queue::GET_ALL;
          centry->downState.requestValue = 11;
          centry->downState.parentIndex = processedInputs_;
          centry->passAtp(pentry_down);
          qchild_.down->insert();
        }
    } // end for processedInputs_

  pentry_down = qparent_.down->getHeadEntry();
  pstate = (ExSequencePrivateState*) pentry_down->pstate;
  request = pentry_down->downState.request;

  // Take any child replies and process them. Return the processed
  // rows as long the parent queue has room.
  //
  while (1)
    {
      // If we have satisfied the parent request (or it was cancelled),
      // then stop processing rows, cancel any outstanding child
      // requests, and set this request to the CANCELLED state.
      //
      if ((pstate->step_ == ExSeq_WORKING_READ) ||
          (pstate->step_ == ExSeq_WORKING_RETURN))
        {
          if ((request == ex_queue::GET_NOMORE) ||
              ((request == ex_queue::GET_N) &&
               (pentry_down->downState.requestValue 
                <= (Lng32)pstate->matchCount_)))
            {
              qchild_.down->cancelRequestWithParentIndex
                (qparent_.down->getHeadIndex());
              pstate->step_ = ExSeq_CANCELLED;
            }
        }

      switch (pstate->step_)
        {
          // ExSeq_CANCELLED
          //
          // Transition to this state from ...
          // 1. ExSeq_Error - After the error has been processed.
          // 2. ExSeq_Working - If enough rows have been returned.
          // 3. ExSeq_Working - If the request was cancelled.
          //
          // Remain in this state until ..
          // 1. All rows from the child including EOD are consumed
          //
          // Transition from this state to ...
          // 1. ExSeq_DONE - In all cases.
          //
        case ExSeq_CANCELLED:
          {
            // There are no extra rows to process from the child yet,
            // so try again later.
            //
            if (qchild_.up->isEmpty())
              {
                return WORK_OK;
              }

            ex_queue_entry * centry = qchild_.up->getHeadEntry();
            ex_queue::up_status child_status = centry->upState.status;

            // If this is the EOD, transition to the ExSeq_DONE state.
            //
            if (child_status == ex_queue::Q_NO_DATA)
                  pstate->step_ = ExSeq_DONE;

            // Discard the child row.
            qchild_.up->removeHead();	    
            break;
          }

        // ExSeq_ERROR
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - a child reply with the type SQLERROR.
        // 2. ExSeq_WORKING_RETURN
        // 3. ExSeq_OVERFLOW_READ
        // 4. ExSeq_OVERFLOW_WRITE
        // Remain in this state until ..
        // 1. The error row has been returned to the parent.
        //
        // Transition from this state to ...
        // 1. ExSeq_CANCELLED - In all cases.
        //
        case ExSeq_ERROR:
          {
            // If there is no room in the parent queue for the reply,
            // try again later.
            //
            if (qparent_.up->isFull())
              // LCOV_EXCL_START
              return WORK_OK;
              // LCOV_EXCL_STOP

            ex_queue_entry *pentry_up = qparent_.up->getTailEntry();

            // Cancel the child request - there must be a child request in
            // progress to get to the ExSeq_ERROR state.
            //
            qchild_.down->cancelRequestWithParentIndex
              (qparent_.down->getHeadIndex());

            // Construct and return the error row.
            //
            if (workAtp_->getDiagsArea()) {
              ComDiagsArea * da = workAtp_->getDiagsArea();
              pentry_up->setDiagsArea(da);
              da->incrRefCount();
              workAtp_->setDiagsArea(0);
            }
            pentry_up->upState.status = ex_queue::Q_SQLERROR;
            pentry_up->upState.parentIndex 
              = pentry_down->downState.parentIndex;
            pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
            pentry_up->upState.setMatchNo(pstate->matchCount_);
            qparent_.up->insert();

            // Transition to the ExSeq_CANCELLED state.
            //
            pstate->step_ = ExSeq_CANCELLED;
            break;
          }

        // ExSeq_WORKING_READ
        //
        // Transition to this state from ...
        // 1. ExSeq_EMPTY - If a request is started.
        // 2. ExSeq_WORKING_RETURN - 
        // 3. ExSeq_OVERFLOW_WRITE - 
        // Remain in this state until ...
        // 1. All child replies including EOD have been processed.
        // 2. A SQLERROR row is received.
        // 3. Enough rows have been returned.
        // 4. The request is cancelled.
        // 5. End of partition is reached
        // Transition from this state to ...
	// 2. ExSeq_ERROR - If an SQLERROR rows is received.
        // 3. ExSeq_CANCELLED - If the request is cancelled.
        // 4. ExSeq_WORKING_RETURN
        // 5. ExSeq_OVERFLOW_WRITE - 
        case ExSeq_WORKING_READ:
          {
            if(!isUnboundedFollowing() && isHistoryFull()) {
              pstate->step_ = ExSeq_WORKING_RETURN;
              break;
            }
            // If there are no replies, try again later.
            //
            if (qchild_.up->isEmpty())
              return WORK_OK;

            ex_queue_entry * centry = qchild_.up->getHeadEntry();
            switch (centry->upState.status)
            {
              // A data row from the child.
              //
            case ex_queue::Q_OK_MMORE:
              {
                tupp_descriptor histTupp;
                workAtp_->copyAtp(pentry_down->getAtp());
                workAtp_->getTupp(myTdb().tuppIndex_) = &histTupp;

                if ( checkPartitionChangeExpr() &&
                       currentHistRowPtr_)
                {
                  workAtp_->getTupp
                    (myTdb().tuppIndex_).setDataPointer(currentHistRowPtr_);

                  // Check whether the partition changed
                  ex_expr::exp_return_type retCode = checkPartitionChangeExpr()->eval(workAtp_, centry->getAtp());
                  
                  if (retCode == ex_expr::EXPR_ERROR)
                  {
                    // LCOV_EXCL_START
                    updateDiagsArea(centry);
                    pstate->step_ = ExSeq_ERROR;
                    break;
                    // LCOV_EXCL_STOP
                  }
                  if ( retCode == ex_expr::EXPR_FALSE)
                  {
                    setPartitionEnd(TRUE);
                    pstate->step_ = ExSeq_END_OF_PARTITION;
                    break;
                  }
                }


                if (isUnboundedFollowing() )
                {
                  if (OLAPBuffersFlushed_)
                  {
                    OLAPBuffersFlushed_ = FALSE;// current row is the first one in first buffer already
                  }
                  else
                  {
                    NABoolean noMemory = 
		      advanceHistoryRow( TRUE /* checkMemoryPressure */);
                    if (noMemory)
                    {
                      pstate->step_ = ExSeq_OVERFLOW_WRITE;
                      cluster_->nextBufferToFlush_ = firstOLAPBuffer_;
		      cluster_->afterLastBufferToFlush_ = NULL;//flush them all

		      // If it is the first overflow, for this partition
		      if ( ! memoryPressureDetected_ ) {
			memoryPressureDetected_ = TRUE;
			
		      } // memory pressure detected

                      break;
                    }
                  }
                }
                else
                {
                  advanceHistoryRow();
                }
 
                workAtp_->getTupp
                  (myTdb().tuppIndex_).setDataPointer(currentHistRowPtr_);

                ex_expr::exp_return_type retCode = ex_expr::EXPR_OK;

                // Apply the read phase sequence function expression to compute 
                // the values of the sequence functions.
                if (sequenceExpr())
                {
                  retCode = sequenceExpr()->eval(workAtp_, centry->getAtp());
                  if (retCode == ex_expr::EXPR_ERROR)
                  {
                    updateDiagsArea(centry);
                    pstate->step_ = ExSeq_ERROR;
                    break;
                  }
                }

                // merge the child's diags area into the work atp
                updateDiagsArea(centry);

                qchild_.up->removeHead();

                break;
              }

              // The EOD from the child. Transition to ExSeq_DONE.
              //
            case ex_queue::Q_NO_DATA:
              {
                setPartitionEnd(TRUE);
                if (isHistoryEmpty())
                {
                  pstate->step_ = ExSeq_DONE;
                  qchild_.up->removeHead();
                }
                else
                {
                  pstate->step_ = ExSeq_END_OF_PARTITION;
                }
              }
              break;

              // An SQLERROR from the child. Transition to ExSeq_ERROR.
              //
            case ex_queue::Q_SQLERROR:
              updateDiagsArea(centry);
              pstate->step_ = ExSeq_ERROR;
              break;
            }
          }
          break;
        // ExSeq_WORKING_RETURN
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - 
        // 2. ExSeq_OVERFLOW_READ - 
        // 3. ExSeq_END_OF_PARTITION - 
        // Remain in this state until ...
        // 1. All rows are returned.
        // 2. A SQLERROR row is received.
        // 3. Enough rows have been returned.
        //
        // Transition from this state to ...
        // 1. ExSeq_DONE - If all the child rows including EOD have 
        //    been processed.
        // 2. ExSeq_ERROR - If an SQLERROR rows is received.
        // 3. ExSeq_CANCELLED - If enough rows have been returned.
        // 4. ExSeq_CANCELLED - If the request is cancelled.
        // 5. ExSeq_WORKING_RETURN        
        // 6. ExSeq_DONE   
	// 7. ExSeq_OVERFLOW_READ     
        case ExSeq_WORKING_RETURN:
          {
            // If there is not room in the parent Queue for the reply,
            // try again later.
            //
            if (qparent_.up->isFull())
              return WORK_OK;

            if(isHistoryEmpty()) 
            {
              ex_queue_entry * centry = NULL;
              if(!qchild_.up->isEmpty()) 
              {
                centry = qchild_.up->getHeadEntry();
              }
              if(centry && (centry->upState.status == ex_queue::Q_NO_DATA)) 
              {
                pstate->step_ = ExSeq_DONE;
                qchild_.up->removeHead();
              } 
              else 
              {
                pstate->step_ = ExSeq_WORKING_READ;

                if (getPartitionEnd())
                {
                  initializeHistory();
                }
              }
              break;
            }

            if(!canReturnRows() && 
               !getPartitionEnd() &&
               !isUnboundedFollowing() &&
               !isOverflowStarted()) // redundant? because not unbounded ... 
            {
              pstate->step_ = ExSeq_WORKING_READ;
              break;
            }
            
            ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
                
            pentry_up->copyAtp(pentry_down);
            // Try to allocate a tupp.
            //
            if (pool_->get_free_tuple(pentry_up->getTupp(myTdb().tuppIndex_),
                                      recLen()))
              // LCOV_EXCL_START
              return WORK_POOL_BLOCKED;
              // LCOV_EXCL_STOP 

            char *tuppData = pentry_up->getTupp
              (myTdb().tuppIndex_).getDataPointer();

            advanceReturnHistoryRow();

            char *histData = currentRetHistRowPtr_; 
            pentry_up->getTupp
              (myTdb().tuppIndex_).setDataPointer(histData);

            ex_expr::exp_return_type retCode = ex_expr::EXPR_OK;
            // Apply the return phase expression
            if(returnExpr())
            {
              retCode = returnExpr()->eval(pentry_up->getAtp(),workAtp_);
              if (retCode == ex_expr::EXPR_ERROR)
              {
                // LCOV_EXCL_START
                pstate->step_ = ExSeq_ERROR;
                break;
                // LCOV_EXCL_STOP
              }
            }

            retCode = ex_expr::EXPR_OK;
            //Apply post predicate expression  
            if (postPred()) 
            {
              retCode = postPred()->eval(pentry_up->getAtp(),pentry_up->getAtp());
              if (retCode == ex_expr::EXPR_ERROR)
              {
                // LCOV_EXCL_START
                pstate->step_ = ExSeq_ERROR;
                break;
                // LCOV_EXCL_STOP
              }
            }

//pentry_up->getAtp()->display("return eval result", myTdb().getCriDescUp());

            //
            // Case-10-030724-7963: we are done pointing the tupp at the
            // history buffer, so point it back to the SQL buffer.
            //
            pentry_up->getTupp
              (myTdb().tuppIndex_).setDataPointer(tuppData);

            switch(retCode) {
            case ex_expr::EXPR_OK:
            case ex_expr::EXPR_TRUE:
            case ex_expr::EXPR_NULL:

              // Copy the row that was computed in the history buffer,
              // to the space previously allocated in the SQL buffer.

              str_cpy_all(tuppData, histData, recLen());

              // Return the processed row.
              //

              // Finalize the queue entry, then insert it
              //
              pentry_up->upState.status = ex_queue::Q_OK_MMORE;
              pentry_up->upState.parentIndex 
                = pentry_down->downState.parentIndex;
              pentry_up->upState.downIndex =
                qparent_.down->getHeadIndex();
              pstate->matchCount_++;
              pentry_up->upState.setMatchNo(pstate->matchCount_);
              qparent_.up->insert();
              break;

              // If the selection predicate returns FALSE,
              // do not return the child row.
              //
            case ex_expr::EXPR_FALSE:
              break;
                    
              // If the selection predicate returns an ERROR,
              // go to the error processing state.
              //
            case ex_expr::EXPR_ERROR:
              // LCOV_EXCL_START
              pstate->step_ = ExSeq_ERROR;
              // LCOV_EXCL_STOP
              break;
            }

            // MV --
            // Now, if there are no errors so far, evaluate the
            // cancel expression
            if ((pstate->step_ != ExSeq_ERROR) && cancelExpr()) 
              {

                // Temporarily point the tupp to the tail of the
                // history buffer for evaluating the
                // expressions.
                //
                pentry_up->getTupp
                  (myTdb().tuppIndex_).setDataPointer(histData);

                retCode = 
                  cancelExpr()->eval(pentry_up->getAtp(),pentry_up->getAtp());
        
                // We are done pointing the tupp at the history
                // buffer, so point it back to the SQL buffer.
                //
                pentry_up->getTupp
                  (myTdb().tuppIndex_).setDataPointer(tuppData);

                if (retCode == ex_expr::EXPR_TRUE)
                  {
                    qchild_.down->cancelRequestWithParentIndex
                      (qparent_.down->getHeadIndex());
                    pstate->step_ = ExSeq_CANCELLED;
                  }
              }

            updateHistRowsToReturn();
            if ( isOverflowStarted() )
            {
              numberOfRowsReturnedBeforeReadOF_ ++;
              if (numberOfRowsReturnedBeforeReadOF_ == maxNumberOfRowsReturnedBeforeReadOF_)
              {
                firstOLAPBufferFromOF_ = currentRetOLAPBuffer_->getNext();
                if (firstOLAPBufferFromOF_ == NULL)
                {
                  firstOLAPBufferFromOF_ = firstOLAPBuffer_;
                }
                for( Int32 i = 0; i < numberOfWinOLAPBuffers_; i++)
                {
                  firstOLAPBufferFromOF_ = firstOLAPBufferFromOF_->getNext();
                  if (firstOLAPBufferFromOF_ == NULL)
                  {
                    firstOLAPBufferFromOF_ = firstOLAPBuffer_;
                  }
                }
                numberOfOLAPBuffersFromOF_ = numberOfOLAPBuffers_ - numberOfWinOLAPBuffers_;

		cluster_->nextBufferToRead_ = firstOLAPBufferFromOF_;
		HashBuffer * afterLast = firstOLAPBufferFromOF_; 
		// last buffer to read into is the current buffer - maybe ?
		for ( Lng32 bufcount = numberOfOLAPBuffersFromOF_ ;
		      bufcount ;
		      bufcount-- ) {
		  afterLast = afterLast->getNext() ;
		  // Don't cycle back if bufcount == 1 because the logic in
		  // Cluster::read relies on the NULL ptr to stop reading
		  if ( bufcount > 1 && ! afterLast ) 
		    afterLast = firstOLAPBuffer_; // cycle back
		}
		// The last buffer to read to is always the current buffer
		// ex_assert ( afterLast == currentRetOLAPBuffer_->getNext(),
		//	    "Miscalculated the last buffer to read into"); 

		cluster_->afterLastBufferToRead_ = afterLast;

                pstate->step_ = ExSeq_OVERFLOW_READ;
              }
            }
          }
          break;

        // ExSeq_END_OF_PARTITION
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - 
        // Transition from this state to ...
        // 1. ExSeq_OVERFLOW_WRITE
        // 2. ExSeq_WORKING_RETURN        

        case ExSeq_END_OF_PARTITION:
        {
          setPartitionEnd(TRUE);
          if (lastRow_  && isUnboundedFollowing())
          {
            ex_assert(currentHistRowPtr_ != NULL, "ExSequenceTcb::work() - currentHistRowPtr_ is a NULL pointer");
            str_cpy_all(lastRow_, currentHistRowPtr_, recLen()); 
          }

          if ( isOverflowStarted() ) // we are overflowing
          {
            cluster_->nextBufferToFlush_ = firstOLAPBuffer_;
	    // do not flush beyond the current buffer
	    cluster_->afterLastBufferToFlush_ = currentOLAPBuffer_->getNext();
            pstate->step_ = ExSeq_OVERFLOW_WRITE;
          }
          else
          {
            pstate->step_ = ExSeq_WORKING_RETURN;
          }
        }
        break;

        // ExSeq_OVERFLOW_WRITE
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - 
        // 2. ExSeq_END_OF_PARTITION - 
        // Remain in this state until ...
        // 1. OLAPbuffers are written to oveflow space.
        // 2. An error occurs
        //
        // Transition from this state to ...
        // 1. ExSeq_OVERFLOW_READ
        // 2. ExSeq_ERROR - If an error occurs
        case ExSeq_OVERFLOW_WRITE:
        {
          if (!overflowEnabled_)
          {
           // LCOV_EXCL_START
           // used for debugging when CmpCommon::getDefault(EXE_BMO_DISABLE_OVERFLOW)is set to off ;
            updateDiagsArea(EXE_OLAP_OVERFLOW_NOT_SUPPORTED);
            pstate->step_ = ExSeq_ERROR;
            break;
            // LCOV_EXCL_STOP
          }
          ex_assert(isUnboundedFollowing(),"");
 
	  if ( ! cluster_->flush(&rc_) ) {  // flush the buffers
            // LCOV_EXCL_START
            // if no errors this code path is not visited
	    if ( rc_ ) 
            { // some error
              updateDiagsArea( rc_);
              pstate->step_ = ExSeq_ERROR;
	      break;
	    }
            // LCOV_EXCL_STOP
	    // not all the buffers are completely flushed. An I/O is pending
            // LCOV_EXCL_START
            // maybe we cane remove in the future
	    return WORK_OK; 
            // LCOV_EXCL_STOP
	  }

	  // At this point -- all the buffers were completely flushed

	  OLAPBuffersFlushed_ = TRUE;

          if (getPartitionEnd())
          {
            firstOLAPBufferFromOF_ = firstOLAPBuffer_;
            numberOfOLAPBuffersFromOF_ = numberOfOLAPBuffers_;

	    cluster_->nextBufferToRead_ = firstOLAPBufferFromOF_;
	    // First time we read and fill all the buffers
	    cluster_->afterLastBufferToRead_ = NULL; 

            pstate->step_ = ExSeq_OVERFLOW_READ;  
          }
          else
          {
            pstate->step_ = ExSeq_WORKING_READ;
          }
        }
        break;
        // ExSeq_OVERFLOW_READ
        //
        // Transition to this state from ...
        // 1. ExSeq_OVERFLOW_WRITE  
        // 2. ExSeq_WORKING_RETURN 
        // Remain in this state until ...
        // 1. OLAPbuffers are read from oveflow space.
        // 2. An error occurs
        //
        // Transition from this state to ...
        // 1. ExSeq_WORKING_RETURN
        // 2. ExSeq_ERROR - If an error occurs
         case ExSeq_OVERFLOW_READ:
        {

            assert(firstOLAPBufferFromOF_ &&
                    isUnboundedFollowing() );

	    if ( ! cluster_->read(&rc_) ) {
              // LCOV_EXCL_START
	      if ( rc_ ) { // some error
                updateDiagsArea( rc_);
		pstate->step_ = ExSeq_ERROR;
		break;
	      }
              // LCOV_EXCL_STOP
	      // not all the buffers are completely read. An I/O is pending
              // LCOV_EXCL_START
	      return WORK_OK;
              // LCOV_EXCL_STOP 
	    }

            numberOfRowsReturnedBeforeReadOF_ = 0;
            pstate->step_ = ExSeq_WORKING_RETURN;
	}
	break;

        // ExSeq_DONE
        //
        // Transition to the state from ...
        // 1. ExSeq_WORKING_RETURN - if all child rows have been processed.
        // 2. ExSeq_CANCELLED - if all child rows have been consumed.
        // 3. ExSeq_EMPTY - if the request was DOA.
        //
        // Remain in this state until ...
        // 1. The EOD is returned to the parent.
        //
        // Transition from this state to ...
        // 1. ExSeq_EMPTY - In all cases.
        //
        case ExSeq_DONE:
          {
            // If there is not any room in the parent's queue, 
            // try again later.
            //
            if (qparent_.up->isFull())
              // LCOV_EXCL_START
              return WORK_OK;
              // LCOV_EXCL_STOP
            
            ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
            pentry_up->upState.status = ex_queue::Q_NO_DATA;
            pentry_up->upState.parentIndex 
              = pentry_down->downState.parentIndex;
            pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
            pentry_up->upState.setMatchNo(pstate->matchCount_);
            
            qparent_.down->removeHead();
            qparent_.up->insert();

            // Re-initialize pstate
            //
            pstate->step_ = ExSeq_EMPTY;
            pstate->matchCount_ = 0;
            workAtp_->release();

            // Initialize the history buffer in preparation for the
            // next request.
            //
            initializeHistory();

            // If there are no more requests, simply return.
            //
            if (qparent_.down->isEmpty())
              return WORK_OK;
           
            // LCOV_EXCL_START
            // If we haven't given to our child the new head
            // index return and ask to be called again.
            //
            if (qparent_.down->getHeadIndex() == processedInputs_)
              return WORK_CALL_AGAIN;

            // Position at the new head of the request queue.
            //
            pentry_down = qparent_.down->getHeadEntry();
            pstate = (ExSequencePrivateState*) pentry_down->pstate;
            request = pentry_down->downState.request; 
            // LCOV_EXCL_STOP
          }
        break;
        } // switch pstate->step_
    } // while
}
예제 #21
0
//////////////////////////////////////////////////////
// work() for ExExeUtilLongRunningTcb
//////////////////////////////////////////////////////
short ExExeUtilLongRunningTcb::work()
{
  short rc = 0;
  Lng32 cliRC = 0;
  Int64 rowsDeleted = 0;
  Int64 transactions = 0;

  // if no parent request, return
  if (qparent_.down->isEmpty())
    return WORK_OK;
  
  // if no room in up queue, won't be able to return data/status.
  // Come back later.
  if (qparent_.up->isFull())
    return WORK_OK;
  
  ex_queue_entry * pentry_down = qparent_.down->getHeadEntry();
  ExExeUtilPrivateState & pstate =
    *((ExExeUtilPrivateState*) pentry_down->pstate);

  // Get the globals stucture of the ESP if this is an ESP
  ExExeStmtGlobals *exeGlob = getGlobals()->castToExExeStmtGlobals();
  ExEspStmtGlobals *espGlob = exeGlob->castToExEspStmtGlobals();


  Int32 espNum = 1;
 
  // this is an ESP?
  if (espGlob != NULL)
  {
     espNum = (Int32) espGlob->getMyInstanceNumber();
  }

  while (1)
    {
      switch (step_)
	{
	case INITIAL_:
	  {
	    step_ = LONG_RUNNING_;
	  }
	break;

	
	case LONG_RUNNING_:
	  {
	    rc = doLongRunning();
	    if ((rc < 0) || (rc == 100)) 
	      {
		finalizeDoLongRunning();
		if (rc <0)
		  step_ = ERROR_;
		else                       // rc == 100 - done with all the transactions.
		  step_ = DONE_;
	      }

            // continue in LONG_RUNNING_ state if (rc >= 0) - success and warning.
	  }
	break;

	
	case DONE_:
	  {
 
	    if (qparent_.up->isFull())
	      return WORK_OK;

	    // Return EOF.
	    ex_queue_entry * up_entry = qparent_.up->getTailEntry();
	    
	    up_entry->upState.parentIndex = 
	      pentry_down->downState.parentIndex;
	    
	    up_entry->upState.setMatchNo(0);
	    up_entry->upState.status = ex_queue::Q_NO_DATA;

	    // before sending the Q_NO_DATA, send the rowcount as well thro'
	    // the diagsArea.
	    
	    getDiagsArea()->setRowCount(getRowsDeleted());

            ComDiagsArea *diagsArea = getDiagAreaFromUpQueueTail();
            if (lrTdb().longRunningQueryPlan())
            {
               (*diagsArea) << DgSqlCode(8450)
                            << DgString0((char*)exeUtilTdb().getTableName())
                            << DgInt0(espNum)
                            << DgInt1((Lng32)getTransactionCount());
            }
	    
	    // insert into parent
	    qparent_.up->insert();
	    
	    //pstate.matches_ = 0;
	    // reset the parameters.
	    step_ = INITIAL_;
	    transactions_ = 0;
	    rowsDeleted_ = 0;
	    initial_ = 1;
	    
	    // clear diags if any
            if (getDiagsArea())
            {
                getDiagsArea()->clear();
            }
    
	    qparent_.down->removeHead();
 
	    return WORK_OK;
	  }
	break;

	case ERROR_:
	  {
	    if (qparent_.up->isFull())
	      return WORK_OK;

	    // Return EOF.
	    ex_queue_entry * up_entry = qparent_.up->getTailEntry();
	    
	    up_entry->upState.parentIndex = 
	      pentry_down->downState.parentIndex;
	    
	    up_entry->upState.setMatchNo(0);
	    up_entry->upState.status = ex_queue::Q_SQLERROR;
	    // get rows deleted so far.
	    getDiagsArea()->setRowCount(getRowsDeleted());
	    ComDiagsArea *diagsArea = up_entry->getDiagsArea();
	    
	    if (diagsArea == NULL)
	      diagsArea = 
		ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap());
            else
              diagsArea->incrRefCount (); // setDiagsArea call below will decr ref count
	    
	    if (getDiagsArea())
	      diagsArea->mergeAfter(*getDiagsArea());
	    
	    up_entry->setDiagsArea (diagsArea);
	    
	    // insert into parent
	    qparent_.up->insert();

	    // clear diags if any, since we already sent the information
	    // up and don't want to send it again as part of DONE_
            if (getDiagsArea())
            {
	      rowsDeleted_ = 0;
	      getDiagsArea()->clear();
            }
	    step_ = DONE_;
	  }
	break;

	} // switch
    } // while

}
예제 #22
0
ExWorkProcRetcode ExCancelTcb::work()
{

  ExMasterStmtGlobals *masterGlobals = 
     getGlobals()->castToExExeStmtGlobals()->castToExMasterStmtGlobals();

  CliGlobals *cliGlobals = masterGlobals->getCliGlobals();

  while ((qparent_.down->isEmpty() == FALSE) && 
         (qparent_.up->isFull() == FALSE))
  {
    ex_queue_entry *pentry_down = qparent_.down->getHeadEntry();
  
    switch (step_)
    {
      case NOT_STARTED:
      {
        if (pentry_down->downState.request == ex_queue::GET_NOMORE)
          step_ = DONE;
        else
        {
          retryCount_ = 0;
          // Priv checking is done during compilation. To support 
          // REVOKE, prevent a prepared CANCEL/SUSPEND/ACTIVATE
          // that was compiled more than 1 second ago from executing 
          // by raising the 8734 error to force an AQR. 
          Int64 microSecondsSinceCompile = NA_JulianTimestamp() - 
              masterGlobals->getStatement()->getCompileEndTime();

          if (microSecondsSinceCompile > 1000*1000)
          {

            ComDiagsArea *diagsArea =
              ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
            *diagsArea << DgSqlCode(-CLI_INVALID_QUERY_PRIVS);
            reportError(diagsArea);
            step_ = DONE;
            break;
          }
          
          // Figure out which MXSSMP broker to use.
          if (cancelTdb().getAction() == ComTdbCancel::CancelByPname)
          {
            int nid = -1;
            int rc = msg_mon_get_process_info(cancelTdb().getCancelPname(),
                                &nid, &pid_);
            switch (rc)
            {
              case XZFIL_ERR_OK:
                cpu_ = (short) nid;
                break;
              case XZFIL_ERR_NOTFOUND:
              case XZFIL_ERR_BADNAME:
              case XZFIL_ERR_NOSUCHDEV:
                {
                  ComDiagsArea *diagsArea =
                    ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

                  *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND);
                  *diagsArea << DgString0(cancelTdb().getCancelPname());
                  reportError(diagsArea);

                  step_ = DONE;
                  break;
                }
              default:
                {
                  char buf[200];
                  str_sprintf(buf, "Unexpected error %d returned from "
                                   "msg_mon_get_process_info", rc);
                  ex_assert(0, buf);
                }
            }
            if (step_ != NOT_STARTED)
              break;
          }
          else if  (cancelTdb().getAction() == ComTdbCancel::CancelByNidPid)
          {
            cpu_ = (short) cancelTdb().getCancelNid();
            pid_ = cancelTdb().getCancelPid();

            // check that process exists, if not report error.
            char processName[MS_MON_MAX_PROCESS_NAME];
            int rc = msg_mon_get_process_name(cpu_, pid_, processName);
            if (XZFIL_ERR_OK == rc)
              ; // good. nid & pid are valid.
            else
            {
              if ((XZFIL_ERR_NOTFOUND  != rc) &&
                  (XZFIL_ERR_BADNAME   != rc) &&
                  (XZFIL_ERR_NOSUCHDEV != rc))
              {
                // Log rc in case it needs investigation later.
               char buf[200];
               str_sprintf(buf, "Unexpected error %d returned from "
                                "msg_mon_get_process_name", rc);
               SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__,
                                               buf, 0);
              }
              char nid_pid_str[32];
              str_sprintf(nid_pid_str, "%d, %d", cpu_, pid_);
              ComDiagsArea *diagsArea =
                    ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

              *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND);
              *diagsArea << DgString0(nid_pid_str);
              reportError(diagsArea);

              step_ = DONE;
              break;
            }
          }
          else
          {
            char * qid = cancelTdb().qid_;
            Lng32 qid_len = str_len(qid);

            // This static method is defined in SqlStats.cpp.  It side-effects
            // the nodeName and cpu_ according to the input qid.
            if (getMasterCpu(
                  qid, qid_len, nodeName_, sizeof(nodeName_) - 1, cpu_) == -1)
            {
              ComDiagsArea *diagsArea =
                ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

              *diagsArea << DgSqlCode(-EXE_RTS_INVALID_QID);

              reportError(diagsArea);

              step_ = DONE;
              break;
            }
          }

          // Testpoints for hard to reproduce problems:
          bool fakeError8028 = false;
          fakeError8028 = (getenv("HP_FAKE_ERROR_8028") != NULL);
          if ((cliGlobals->getCbServerClass() == NULL) || fakeError8028)
          {
            ComDiagsArea *diagsArea = 
              ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

            *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND);
            *diagsArea << DgString0("$ZSM000");

            reportError(diagsArea);

            step_ = DONE;
            break;
          }

          ComDiagsArea *diagsArea = NULL;
          bool fakeError2024 = false;
          fakeError2024 = (getenv("HP_FAKE_ERROR_2024") != NULL);
        
          if (fakeError2024)
          {
            cbServer_ = NULL;
            diagsArea =
                  ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
            if (getenv("HP_FAKE_ERROR_8142"))
            {
               *diagsArea << DgSqlCode(-8142);
               *diagsArea << DgString0(__FILE__);
               *diagsArea << DgString1("cbServer_ is NULL");
            }
            else
               *diagsArea << DgSqlCode(-2024);
          }
          else
            cbServer_ = cliGlobals->getCbServerClass()->allocateServerProcess(
                      &diagsArea, 
                      cliGlobals->getEnvironment()->getHeap(),
                      nodeName_,
                      cpu_,
                      IPC_PRIORITY_DONT_CARE,
                      FALSE,  // usesTransactions 
                      TRUE,   // waitedCreation
                      2       // maxNowaitRequests -- cancel+(1 extra).
                      );


          if (cbServer_ == NULL || cbServer_->getControlConnection() == NULL)
          {
            ex_assert(diagsArea != NULL, 
                      "allocateServerProcess failed, but no diags");

            // look for SQLCode 2024 
            // "*** ERROR[2024] Server Process $0~string0 
            // is not running or could not be created. Operating System 
            // Error $1~int0 was returned."
            // Remap to cancel-specfic error 8028.
            if (diagsArea->contains(-2024)  &&
                cancelTdb().actionIsCancel())
            {
              diagsArea->deleteError(diagsArea->returnIndex(-2024));
              reportError(diagsArea, true, EXE_CANCEL_PROCESS_NOT_FOUND, 
                          nodeName_, cpu_);
            }
            else
              reportError(diagsArea);

            step_ = DONE;
            break;
          }

          // the reportError method was not called -- see break above.
          if (diagsArea != NULL)
            diagsArea->decrRefCount();

          //Create the stream on the IpcHeap, since we don't dispose 
          // of it immediately.  We just add it to the list of completed 
          // messages in the IpcEnv, and it is disposed of later.

          cancelStream_  = new (cliGlobals->getIpcHeap())
                CancelMsgStream(cliGlobals->getEnvironment(), this);

          cancelStream_->addRecipient(cbServer_->getControlConnection());

        }

        step_ = SEND_MESSAGE;

        break;
      }  // end case NOT_STARTED

#pragma warning (disable : 4291)

      case SEND_MESSAGE:
      {
        RtsHandle rtsHandle = (RtsHandle) this;

        if (cancelTdb().actionIsCancel())
        {
          Int64 cancelStartTime = JULIANTIMESTAMP();

          Lng32 firstEscalationInterval = cliGlobals->currContext()->
                    getSessionDefaults()->getCancelEscalationInterval();

          Lng32 secondEscalationInterval = cliGlobals->currContext()->
                    getSessionDefaults()->getCancelEscalationMxosrvrInterval();

          NABoolean cancelEscalationSaveabend = cliGlobals->currContext()->
                    getSessionDefaults()->getCancelEscalationSaveabend();

          bool cancelLogging = (TRUE == cliGlobals->currContext()->
                    getSessionDefaults()->getCancelLogging());

          CancelQueryRequest *cancelMsg = new (cliGlobals->getIpcHeap()) 
            CancelQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), 
                      cancelStartTime,
                      firstEscalationInterval,
                      secondEscalationInterval,
                      cancelEscalationSaveabend,
                      cancelTdb().getCommentText(),
                      str_len(cancelTdb().getCommentText()),
                      cancelLogging,
                      cancelTdb().action_ != ComTdbCancel::CancelByQid,
                      pid_,
                      cancelTdb().getCancelPidBlockThreshold());

#pragma warning (default : 4291)

          *cancelStream_ << *cancelMsg;

          cancelMsg->decrRefCount();
        }
        else if (ComTdbCancel::Suspend == cancelTdb().action_)
        {

          bool suspendLogging = (TRUE == cliGlobals->currContext()->
                    getSessionDefaults()->getSuspendLogging());

#pragma warning (disable : 4291)
          SuspendQueryRequest * suspendMsg = new (cliGlobals->getIpcHeap()) 
            SuspendQueryRequest(rtsHandle, cliGlobals->getIpcHeap(),
                                ComTdbCancel::Force ==
                                cancelTdb().forced_,
                                suspendLogging);
#pragma warning (default : 4291)

          *cancelStream_ << *suspendMsg;

          suspendMsg->decrRefCount();
        }
        else
        {
          ex_assert(
            ComTdbCancel::Activate == cancelTdb().action_,
            "invalid action for ExCancelTcb");

          bool suspendLogging = (TRUE == cliGlobals->currContext()->
                    getSessionDefaults()->getSuspendLogging());

#pragma warning (disable : 4291)
          ActivateQueryRequest * activateMsg = new (cliGlobals->getIpcHeap()) 
            ActivateQueryRequest(rtsHandle, cliGlobals->getIpcHeap(),
                                 suspendLogging);
#pragma warning (default : 4291)

          *cancelStream_ << *activateMsg;

          activateMsg->decrRefCount();
        }

        if ((cancelTdb().getAction() != ComTdbCancel::CancelByPname) &&
            (cancelTdb().getAction() != ComTdbCancel::CancelByNidPid))
        {
          char * qid = cancelTdb().qid_;
          Lng32 qid_len = str_len(qid);

#pragma warning (disable : 4291)
          RtsQueryId *rtsQueryId = new (cliGlobals->getIpcHeap())
                           RtsQueryId( cliGlobals->getIpcHeap(), qid, qid_len);
#pragma warning (default : 4291)

          *cancelStream_ << *rtsQueryId;
          rtsQueryId->decrRefCount();
        }

        // send a no-wait request to the cancel broker.
        cancelStream_->send(FALSE);

        step_ = GET_REPLY;    
        // Come back when I/O completes.
        return WORK_OK; 

        break;
      }  // end case SEND_MESSAGE

      case GET_REPLY:
      {

        // Handle general IPC error.
        bool fakeError201 = false;
        fakeError201 = (getenv("HP_FAKE_ERROR_201") != NULL);
        if ((cbServer_->getControlConnection()->getErrorInfo() != 0) ||
            fakeError201)
        {
          ComDiagsArea *diagsArea = 
            ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

          cbServer_->getControlConnection()->
              populateDiagsArea( diagsArea, getGlobals()->getDefaultHeap());

          if (fakeError201)
          {
            *diagsArea << DgSqlCode(-2034) << DgInt0(201)
                       << DgString0("I say") << DgString1("control broker");
          }

          if (diagsArea->contains(-8921))
          {
            // Should not get timeout error 8921. Get a core-file
            // of the SSMP and this process too so that this can be
            // debugged.
            cbServer_->getControlConnection()->
              dumpAndStopOtherEnd(true, false);
            genLinuxCorefile("Unexpected timeout error");
          }

          reportError(diagsArea);

          step_ = DONE;
          break;
        }

        // See if stream has the reply yet.
        if (!cancelStream_->moreObjects())
          return WORK_OK; 

#pragma warning (disable : 4291)

        ControlQueryReply *reply = new (cliGlobals->getIpcHeap()) 
              ControlQueryReply(INVALID_RTS_HANDLE, cliGlobals->getIpcHeap());

#pragma warning (default : 4291)

        *cancelStream_ >> *reply;

        if (reply->didAttemptControl())
        {
          // yeaah!
          cancelStream_->clearAllObjects();
        }
        else
        {
          if (cancelStream_->moreObjects() &&
              cancelStream_->getNextObjType() == IPC_SQL_DIAG_AREA)
          {
            ComDiagsArea *diagsArea = 
              ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

            *cancelStream_ >> *diagsArea;
            cancelStream_->clearAllObjects();

            if ( retryQidNotActive_ &&
                (diagsArea->mainSQLCODE() == -EXE_SUSPEND_QID_NOT_ACTIVE) &&
                (++retryCount_ <= 60))
            {
              SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, 
                                             "Retrying error 8672.", 0);
              DELAY(500);
              diagsArea->decrRefCount();
              step_ = SEND_MESSAGE;
              break;
            }

            reportError(diagsArea);
          }
          else 
            ex_assert(0, "Control failed, but no diagnostics.");
        }

        step_ = DONE;
        break;
      }
      case DONE: 
      {
        if (cancelStream_)
        {
          cancelStream_->addToCompletedList();
          cancelStream_ = NULL;
        }
        if (cbServer_)
        {
          cbServer_->release();
          cbServer_ = NULL;
        }

        ex_queue_entry * up_entry = qparent_.up->getTailEntry();
        up_entry->copyAtp(pentry_down);
        up_entry->upState.parentIndex = pentry_down->downState.parentIndex;
        up_entry->upState.downIndex = qparent_.down->getHeadIndex();     
        up_entry->upState.setMatchNo(1);
        up_entry->upState.status = ex_queue::Q_NO_DATA;
        qparent_.up->insert();

        qparent_.down->removeHead();

        step_ = NOT_STARTED;
        break;
      }
      default:
        ex_assert( 0, "Unknown step_.");
    }
short ExTupleFlowTcb::work()
{
  // This is some sort of a hack to fix the problems with the number of rows
  // inserted returned to the user for packed tables. For these tables, rows
  // are packed (by the Pack node which is the left child of this tuple flow)
  // before they are sent off to DP2. DP2 has no idea that it's actually
  // inserting multiple logical rows (as perceived by the user). However,
  // there is actually a hidden count of logical rows stored as the first 4
  // bytes of the packed row. This counter is supposed to keep track of a sum
  // of this number in each packed row it gets from the left. When all
  // insertions are done, this sum is used to override what's stored by the
  // PA node in the executor global area the number of rows inserted. This is
  // not a very good place to have this fix, but since this is a low-priority
  // problem at this time, here we are.
  //                                                       
  // 
  // NB: The code introduced for this fix 
  //      could be safely removed if desired. Also, all changes are within
  //     this file.
  // 

  if (qParent_.down->isEmpty())
    return WORK_OK;
  
  ex_queue_entry * pentry_down = qParent_.down->getHeadEntry();
  ExTupleFlowPrivateState &  pstate = 
    *((ExTupleFlowPrivateState*) pentry_down->pstate);

  if ((tflowTdb().userSidetreeInsert()) &&
      (pentry_down->downState.request == ex_queue::GET_EOD) &&
      (NOT pstate.parentEOD_))
    {
      pstate.step_ = MOVE_EOD_TO_TGT_;
    }
  else if ((pstate.step_ != DONE_) &&
     (pstate.step_ != CANCELLED_) &&
      (pentry_down->downState.request == ex_queue::GET_NOMORE))
    {
      if (pstate.step_ == EMPTY_)
        pstate.step_ = DONE_;
      else
        pstate.step_ = CANCELLED_;
    }

  while (1)
    {
      switch (pstate.step_)
	{
	case EMPTY_:
	  {
	    if (qSrc_.down->isFull())
	      return WORK_OK;

	    ex_queue_entry * src_entry = qSrc_.down->getTailEntry();

	    src_entry->downState.request = pentry_down->downState.request;
	    src_entry->downState.requestValue = 
	      pentry_down->downState.requestValue;

	    if ((tflowTdb().firstNRows() >= 0) &&
		(pentry_down->downState.request != ex_queue::GET_N))
	      {
		src_entry->downState.request = ex_queue::GET_N;
		src_entry->downState.requestValue = tflowTdb().firstNRows();
	      }

	    src_entry->downState.parentIndex = 
              qParent_.down->getHeadIndex();

	    src_entry->passAtp(pentry_down);
	    
	    qSrc_.down->insert();

	    // just checking to make sure we got a diags area from the CLI if we are 
	    // executing a non-tomic insert. This is done now so that we don't have to do it in multiple
	    // places later.
	    if (tflowTdb().isNonFatalErrorTolerated()) {
	      ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea();
	      ex_assert(cliDiagsArea, "In Tupleflow : Non-Atomic insert received no diags area from the CLI");
	    }

	    pstate.parentEOD_ = FALSE;
	    pstate.srcEOD_ = FALSE;
            pstate.matchCount_ = 0;
            pstate.tgtRequests_ = 0;
	    pstate.tgtRowsSent_ = FALSE;
	    pstate.noOfUnPackedRows_ = 0;
	    pstate.srcRequestCount_ = -1;
            pstate.nonFatalErrorSeen_ = FALSE;
	    // Set startRightIndex_ so that CancelReques doesn't do anything.
	    pstate.startRightIndex_ = pstate.srcRequestCount_;
	    pstate.step_ = MOVE_SRC_TO_TGT_;
	  }
	  break;

	case MOVE_SRC_TO_TGT_:
	  {
	    // if there are some rows in source up queue, move them to target.
	    while ((! qSrc_.up->isEmpty()) && (! qTgt_.down->isFull())
                     && (pstate.step_ != HANDLE_ERROR_))
	      {
		ex_queue_entry * src_entry = qSrc_.up->getHeadEntry();
		ex_queue_entry * tgt_entry = qTgt_.down->getTailEntry();

		switch (src_entry->upState.status)
		  {
		  case ex_queue::Q_OK_MMORE:
		    {
		      // move this source row to target.
                      
                      // LCOV_EXCL_START
                      // BEGIN:  - Read note at beginning of work().
                      // 
                      if (tcbSrc_->getNodeType() == ComTdb::ex_PACKROWS)
                      {
                        char* packTuppPtr =
                          src_entry->getTupp(src_entry->numTuples()-1)
			  .getDataPointer();
                        Int32 noOfRows = *((Int32 *)packTuppPtr);
                        pstate.noOfUnPackedRows_ += (noOfRows - 1);
			
                      }
                      //
                      // END:- Read note at beginning of work().
                      // LCOV_EXCL_STOP

		      pstate.srcRequestCount_++;
		      tgt_entry->downState.request = 
			pentry_down->downState.request;
		      tgt_entry->downState.requestValue = 
			pentry_down->downState.requestValue;
		      tgt_entry->downState.parentIndex = 
                       (Lng32) pstate.srcRequestCount_;
		      tgt_entry->copyAtp(src_entry);
		      qTgt_.down->insert();
                      pstate.tgtRequests_++;
	              pstate.tgtRowsSent_ = TRUE;
		      qSrc_.up->removeHead();
		    }
		    break;

		  case ex_queue::Q_NO_DATA:
		    {
		      if ((tflowTdb().vsbbInsertOn()) &&
	                  (pstate.tgtRowsSent_ == TRUE))
			{
			  if (tflowTdb().userSidetreeInsert())
			    {
			      tgt_entry->downState.request = 
				ex_queue::GET_EOD_NO_ST_COMMIT;
			    }
			  else
			    {
			      tgt_entry->downState.request = 
				ex_queue::GET_EOD;
			    }

			  tgt_entry->downState.requestValue = 
			    pentry_down->downState.requestValue;
			  tgt_entry->downState.parentIndex = 
                            (Lng32) pstate.srcRequestCount_;
			  tgt_entry->copyAtp(src_entry);
			  
			  qTgt_.down->insert();
                          pstate.tgtRequests_++;
			}

                      // LCOV_EXCL_START
	              if ((pstate.tgtRowsSent_ == FALSE) &&
			  (src_entry->getDiagsArea()))
			{
			  // a warning is returned with EOD and
			  // nothing else was returned from source.
			  // Move warning to parent's up queue.
			  if (qParent_.up->isFull())
			    return WORK_OK;

			  ex_queue_entry * up_entry = 
			    qParent_.up->getTailEntry();
			  up_entry->setDiagsArea(src_entry->getDiagsArea());
			}
                      // LCOV_EXCL_STOP

		      qSrc_.up->removeHead();
		      
		      pstate.srcEOD_ = TRUE;
                      
                      // LCOV_EXCL_START
		      if (tflowTdb().sendEODtoTgt())
			pstate.step_ = MOVE_EOD_TO_TGT_;
                      // LCOV_EXCL_STOP
		    }
		    break;
		    
		  case ex_queue::Q_SQLERROR:
                    {
	              if (qParent_.up->isFull())
	                return WORK_OK;
	    
	              ex_queue_entry * pentry = qParent_.up->getTailEntry();
		      ComDiagsArea * da = src_entry->getDiagsArea();
		      ex_assert(da, "We have a Q_SQLERROR in Tupleflow but no diags area");
		      
		      if (tflowTdb().isNonFatalErrorTolerated() &&
			 (da->getNextRowNumber(ComCondition::NONFATAL_ERROR) == 
			  ComCondition::NONFATAL_ERROR)) 
			{
			  pstate.nonFatalErrorSeen_ = TRUE;		
			}
		      else 
			{
			  pstate.step_ = HANDLE_ERROR_;
			  pstate.nonFatalErrorSeen_ = FALSE;
			}

		      pstate.srcRequestCount_++;
		      if(tflowTdb().isRowsetIterator())
	                da->setAllRowNumber((Lng32) pstate.srcRequestCount_); 

                      ComDiagsArea *accumulatedDiagsArea = pentry->getDiagsArea();
			if (accumulatedDiagsArea)
			  {
			    accumulatedDiagsArea->mergeAfter(*da);
			    if (!(accumulatedDiagsArea->canAcceptMoreErrors()) && 
				tflowTdb().isNonFatalErrorTolerated()) 
			      {
				pstate.nonFatalErrorSeen_ = FALSE;
				pstate.step_ = HANDLE_ERROR_; 
			      }
			  }
                        else
			  {
			    pentry->setDiagsArea(da);
			    da->incrRefCount();
			    accumulatedDiagsArea = da ;
			    if (tflowTdb().isNonFatalErrorTolerated()) 
			      {
				ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea();
				da->setLengthLimit(cliDiagsArea->getLengthLimit());
			      }
			  }

			// For Non-Fatal errors we will remove this Q_SQLERROR reply from the 
			// left child right below as we will continue to stay in this state (MOVE_SRC_TO_TGT_).
			// For fatal errors this Q_SQLERROR reply is removed in HANDLE_ERROR step to which
			// we will transition immediately.
			if (pstate.nonFatalErrorSeen_ == TRUE)
			  qSrc_.up->removeHead();	
                    }
                    break;

		  case ex_queue::Q_REC_SKIPPED:
                    {
		      pstate.srcRequestCount_++;
		      ComDiagsArea * da = src_entry->getDiagsArea();
		      if (da)
			pstate.nonFatalErrorSeen_ = TRUE;		  
		      qSrc_.up->removeHead();
                    }
                    break;

		  default:
		    {
		      ex_assert(0, "ExTupleFlowTcb::work() Error returned from src"); // LCOV_EXCL_LINE
		    }
		    break;
		  } // switch

	      } // while
	    
            // if the child reply is not an Q_SQLERROR, then process target
            if ((pstate.step_ != HANDLE_ERROR_) &&
		(pstate.step_ != MOVE_EOD_TO_TGT_))
	      pstate.step_ = PROCESS_TGT_;
	  } // MOVE_SRC_TO_TGT
	  break;

	case MOVE_EOD_TO_TGT_:
	  {
	    pstate.parentEOD_ = TRUE;

	    if (qTgt_.down->isFull())
	      return WORK_OK;

	    ex_queue_entry * tgt_entry = qTgt_.down->getTailEntry();
	    tgt_entry->downState.request = ex_queue::GET_EOD;
	    
	    tgt_entry->downState.requestValue = 
	      pentry_down->downState.requestValue;
	    tgt_entry->downState.parentIndex = 
	      qParent_.down->getHeadIndex();
	    //tgt_entry->passAtp(pentry_down);
	    
	    qTgt_.down->insert();

	    pstate.tgtRequests_++;

            // LCOV_EXCL_START
	    if (tflowTdb().sendEODtoTgt())
	      pstate.srcEOD_ = TRUE;
            // LCOV_EXCL_STOP
	    else
	      pstate.srcEOD_ = FALSE;

	    pstate.step_ = PROCESS_TGT_;
	  }
	break;

	case PROCESS_TGT_:
	  {
	    while (! qTgt_.up->isEmpty()  &&  pstate.step_ != HANDLE_ERROR_)
	      {
		ex_queue_entry * tgt_entry = qTgt_.up->getHeadEntry();
		switch (tgt_entry->upState.status)
		  {
		  case ex_queue::Q_OK_MMORE:
		    {
		      if (!tflowTdb().isNonFatalErrorTolerated()) 
			{
			  // ex_assert(0, "ExTupleFlowTcb::work() OK_MMORE from tgt");
			  if (qParent_.up->isFull())
			    return WORK_OK;

			  ex_queue_entry * pentry = qParent_.up->getTailEntry();

			  pentry->upState.status = ex_queue::Q_OK_MMORE;
			  pentry->upState.downIndex = qParent_.down->getHeadIndex();
			  pentry->upState.parentIndex = pentry_down->downState.parentIndex;
			  pentry->upState.setMatchNo(pstate.matchCount_);
			  
			  // copy input tupps from parent request
			  pentry->copyAtp(pentry_down);

			  // copy child's atp to
			  // the output atp (to parent's up queue)
			  pentry->copyAtp(tgt_entry);

			  // insert into parent up queue
			  qParent_.up->insert();	  
			}
		      else 
			{
			  ComDiagsArea * da = tgt_entry->getDiagsArea();
			  ex_assert(da, "We have a Q_OK_MMORE in Tupleflow but no diags area");
			  if (da->mainSQLCODE() != 0) {
			    // Non-atomic Rowsets sends OK_MMORE with non-empty diags from child
			    // empty diags (mainsqlcode == 0) implies OK_MMORE sent by ignoreDupKey code
			    // when NAR is on, for -8102 error.  Just consume the OK_MMORE.
			    
			    if(tflowTdb().isRowsetIterator()) 
			      {
				da->setAllRowNumber(Lng32 (tgt_entry->upState.parentIndex));
			      }
			    
			    pstate.nonFatalErrorSeen_ = TRUE;
			    ex_queue_entry * pentry = qParent_.up->getTailEntry();
			    ComDiagsArea *accumulatedDiagsArea = pentry->getDiagsArea();
			    if (accumulatedDiagsArea)
			      {
				accumulatedDiagsArea->mergeAfter(*da);
				if (!(accumulatedDiagsArea->canAcceptMoreErrors()) && 
				    tflowTdb().isNonFatalErrorTolerated()) 
				  {
				    pstate.nonFatalErrorSeen_ = FALSE;
				    pstate.step_ = HANDLE_ERROR_; 
				  }
			      }
			    else
			      {
				pentry->setDiagsArea(da);
				da->incrRefCount();
				if (tflowTdb().isNonFatalErrorTolerated()) {
				  ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea();
				  da->setLengthLimit(cliDiagsArea->getLengthLimit());
				}
			      }
			  }
			}

		      qTgt_.up->removeHead();
		    }
		  break;
		  
		  case ex_queue::Q_NO_DATA:
		    {
                      ComDiagsArea * da = tgt_entry->getDiagsArea();
                      if (da)
                        {
	                  ex_queue_entry * pentry = qParent_.up->getTailEntry();
                          ComDiagsArea *accumulatedDiagsArea = pentry->getDiagsArea();
                          if (accumulatedDiagsArea) 
                            accumulatedDiagsArea->mergeAfter(*da);
                          else
                            {
	                      pentry->setDiagsArea(da);
                              da->incrRefCount();
			      if (tflowTdb().isNonFatalErrorTolerated()) {
				ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea();
				da->setLengthLimit(cliDiagsArea->getLengthLimit());
			      }
                            }
                        }
		      pstate.matchCount_ += tgt_entry->upState.getMatchNo();
		      qTgt_.up->removeHead();
		      pstate.tgtRequests_--;
		      pstate.startRightIndex_++;
		    }
		    break;
		    
		  case ex_queue::Q_SQLERROR:
                    {
		      if (qParent_.up->isFull())
			return WORK_OK;
	    
		      ex_queue_entry * pentry = qParent_.up->getTailEntry();
		      pentry->copyAtp(tgt_entry);  
		      pstate.nonFatalErrorSeen_ = FALSE;
		      pstate.step_ = HANDLE_ERROR_; 

		      if(tflowTdb().isRowsetIterator()) 
		      {
			ex_queue_entry * pentry = qParent_.up->getTailEntry();
	                ComDiagsArea *da = pentry->getDiagsArea();
			ex_assert(da, "To set RowNumber, an error condition must be present in the diags area");
	                da->setAllRowNumber(Lng32 (tgt_entry->upState.parentIndex));		      
		      }
	    
                    }
                    break;
                             
		  default:
		    {
		      ex_assert(0, "ExTupleFlowTcb::work() Error returned from tgt"); // LCOV_EXCL_LINE
		    }
		    break;
		    
		  } // switch
		
	      } // while 

            if (pstate.step_ == HANDLE_ERROR_)
              break;

	    // if source has returned EOD,
	    // and there are no pending requests in target's down
	    // queue, then we are done with this parent request.
	    if (((pstate.srcEOD_ == TRUE) ||
		 (pstate.parentEOD_ == TRUE)) &&
		(qTgt_.down->isEmpty()))
	      pstate.step_ = DONE_;
	    else
	      {
		if (NOT pstate.parentEOD_)
		  pstate.step_ = MOVE_SRC_TO_TGT_;

	        if (qSrc_.up->isEmpty() || qTgt_.down->isFull())
	 	  return WORK_OK;
	        else
		  return WORK_CALL_AGAIN;
	      }
	  }
	  break;

        case HANDLE_ERROR_:
          {
	     ex_queue_entry * pentry = qParent_.up->getTailEntry();

 	     pentry->upState.status = ex_queue::Q_SQLERROR;
	     pentry->upState.downIndex = qParent_.down->getHeadIndex();
	     pentry->upState.parentIndex = pentry_down->downState.parentIndex;
	     pentry->upState.setMatchNo(pstate.matchCount_);

	     ComDiagsArea *da = pentry->getDiagsArea();
	     if (tflowTdb().isNonFatalErrorTolerated() &&
		  !(da->canAcceptMoreErrors())) {
	      ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea();
	      da->removeLastErrorCondition();
	      *da << DgSqlCode(-EXE_NONATOMIC_FAILURE_LIMIT_EXCEEDED) 
			      << DgInt0(cliDiagsArea->getLengthLimit());
	     }
	    
	     // insert into parent up queue
	     qParent_.up->insert();
   
             pstate.step_ = CANCELLED_;
          }
          break;

        case CANCELLED_:
          {
            qSrc_.down->cancelRequestWithParentIndex(qParent_.down->getHeadIndex());

            // Cancel all the outstanding requests that have been sent to the target.
            // Cancel all requests within given range (inclusive)
            qTgt_.down->cancelRequestWithParentIndexRange((queue_index)pstate.startRightIndex_+1,
                                                          (queue_index)pstate.srcRequestCount_);
            pstate.startRightIndex_ = pstate.srcRequestCount_;

            //ignore all rows from source child, till Q_NO_DATA is reached
            while ((pstate.srcEOD_ != TRUE) && (!qSrc_.up->isEmpty()))
              {
	        ex_queue_entry * src_entry = qSrc_.up->getHeadEntry();
                switch(src_entry->upState.status)
                  {
                    case ex_queue::Q_OK_MMORE:
                    case ex_queue::Q_SQLERROR:
		    case ex_queue::Q_REC_SKIPPED:
                      {
                        qSrc_.up->removeHead();
                      }
                      break;

                    case ex_queue::Q_NO_DATA:
                      {
                        pstate.srcEOD_ = TRUE;
                        qSrc_.up->removeHead();
                      }
                      break;
                        
                    default:
                      {
		        ex_assert(0, "ExTupleFlowTcb::work() Error returned from src"); // LCOV_EXCL_LINE
		      }
		      break;
                  }
              }

            //ignore all rows from target child, till Q_NO_DATA is reached
            while (pstate.tgtRequests_ && !qTgt_.up->isEmpty())
              {
	        ex_queue_entry * tgt_entry = qTgt_.up->getHeadEntry();
                switch(tgt_entry->upState.status)
                  {
                    case ex_queue::Q_OK_MMORE:
                    case ex_queue::Q_SQLERROR:
                      {
                        qTgt_.up->removeHead();
                      }
                      break;

                    case ex_queue::Q_NO_DATA:
                      {
                        qTgt_.up->removeHead();
                        pstate.tgtRequests_--;
                      }
                      break;
                    
                    default:
                      {
                        ex_assert(0, "ExTupleFlowTcb::work() Error returned from tgt"); // LCOV_EXCL_LINE
                      }
		      break;
                  }
              }

            // if both source and target returned all the rows,
            // insert Q_SQLERROR into the parent up queue
            if ((pstate.srcEOD_ == TRUE)  &&  !pstate.tgtRequests_)
              {
	        pstate.step_ = DONE_; 
              }
            else
              return WORK_OK;
          }
          break;
	  
	case DONE_:
	  {
	    if (qParent_.up->isFull())
	      return WORK_OK;
	    
	    ex_queue_entry * pentry = qParent_.up->getTailEntry();

	    if (pstate.nonFatalErrorSeen_) {
	      ComDiagsArea *da = pentry->getDiagsArea();
	      ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea();
	      ex_assert((da || cliDiagsArea), "We have non-fatal errors in Tupleflow but no diags area");
	      if (cliDiagsArea) {
		  if (da)
		    da->mergeAfter(*cliDiagsArea);
		  else
		    {
		      pentry->setDiagsArea(cliDiagsArea);
		      cliDiagsArea->incrRefCount();
		    }
	      } 

	      if (cliDiagsArea->canAcceptMoreErrors()) {
	      	  ComDiagsArea *mergedDiagsArea = pentry->getDiagsArea();
		  // used to make mainSQLCODE() return 30022 or 30035.
		  mergedDiagsArea->setNonFatalErrorSeen(TRUE);
		  NABoolean anyRowsAffected = FALSE;


		  // This tupleflow should be in the master for
		  // non-atomic rowsets.
		  ExMasterStmtGlobals *g = getGlobals()->
			castToExExeStmtGlobals()->castToExMasterStmtGlobals();
		  ex_assert(g, "Rowset insert has a flow node that is not in the master executor");
		  if (g->getRowsAffected() > 0)
		    anyRowsAffected = TRUE;
		  
		  if (anyRowsAffected)
		      *mergedDiagsArea << DgSqlCode(EXE_NONFATAL_ERROR_SEEN);
		  else 
		      *mergedDiagsArea << DgSqlCode(EXE_NONFATAL_ERROR_ON_ALL_ROWS);

	      } // we exceeded the Nonfatal error limit when merging with the CLI diags area
	      else {
		pstate.step_ = HANDLE_ERROR_;
		// will prevent us from merging the diags areas again
		pstate.nonFatalErrorSeen_ = FALSE ;
		break ;
	      }
	    }
	    
	    pentry->upState.status = ex_queue::Q_NO_DATA;
	    pentry->upState.downIndex = qParent_.down->getHeadIndex();
	    pentry->upState.parentIndex = pentry_down->downState.parentIndex;
	    pentry->upState.setMatchNo(pstate.matchCount_);

            // LCOV_EXCL_START
            // BEGIN:  Read note at beginning of work().
            //
            if(pstate.noOfUnPackedRows_ != 0)
            {
	      ComDiagsArea *da = pentry->getDiagsArea();
	      if (da == NULL)
		{
		  da = ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
		  pentry->setDiagsArea(da);
		}
	      da->addRowCount(pstate.noOfUnPackedRows_);
              pstate.noOfUnPackedRows_ = 0;
            }
            //
            // END: - Read note at beginning of work().
            // LCOV_EXCL_STOP

	    // if stats are to be collected, collect them.
	    if (getStatsEntry())
	      {
		// nothing yet returned from right child or returned
		// to parent.
		getStatsEntry()->setActualRowsReturned(0);
	      }
	    
	    // insert into parent up queue
	    qParent_.up->insert();
	    
	    pstate.step_ = EMPTY_;
	    qParent_.down->removeHead();	

	    return WORK_CALL_AGAIN;  // check for more down requests

	  }
	  break;

	} // switch pstate.step_
    } // while
  
#pragma nowarn(203)   // warning elimination 
  return 0;
#pragma warn(203)  // warning elimination 
}
void ExHdfsFastExtractTcb::insertUpQueueEntry(ex_queue::up_status status, ComDiagsArea *diags, NABoolean popDownQueue)
{

  ex_queue_entry *upEntry = qParent_.up->getTailEntry();
  ex_queue_entry *downEntry = qParent_.down->getHeadEntry();
  ExFastExtractPrivateState &privateState = *((ExFastExtractPrivateState *) downEntry->pstate);

  // Initialize the up queue entry.
  //
  // copyAtp() will copy all tuple pointers and the diags area from
  // the down queue entry to the up queue entry.
  //
  // When we return Q_NO_DATA if the match count is > 0:
  // * assume down queue diags were returned with the Q_OK_MMORE entries
  // * release down queue diags before copyAtp()
  //
  if (status == ex_queue::Q_NO_DATA && privateState.matchCount_ > 0)
  {
    downEntry->setDiagsArea(NULL);
    upEntry->copyAtp(downEntry);
  }
  else
  {
    upEntry->copyAtp(downEntry);
    downEntry->setDiagsArea(NULL);
  }

  upEntry->upState.status = status;
  upEntry->upState.parentIndex = downEntry->downState.parentIndex;
  upEntry->upState.downIndex = qParent_.down->getHeadIndex();
  upEntry->upState.setMatchNo(privateState.matchCount_);

  // rows affected code (below) medeled after ex_partn_access.cpp
  ExMasterStmtGlobals *g = getGlobals()->castToExExeStmtGlobals()->castToExMasterStmtGlobals();
  if (!g)
  {
    ComDiagsArea *da = upEntry->getDiagsArea();
    if (da == NULL)
    {
      da = ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
      upEntry->setDiagsArea(da);
    }
    da->addRowCount(privateState.matchCount_);
  }
  else
  {
    g->setRowsAffected(privateState.matchCount_);
  }


  //
  // Insert into up queue
  qParent_.up->insert();

  // Optionally remove the head of the down queue
  if (popDownQueue)
  {
    privateState.init();
    qParent_.down->removeHead();
  }
}
예제 #25
0
void ex_queue::injectErrorOrCancel()
{
#ifdef _DEBUG
  ex_queue_entry *qe = getQueueEntry(tail_-1);

  // DO the ol' switcheroo, but not every time.
  ULng32 freq = insertSubtask_->getTcb()->getGlobals()->getInjectErrorAtQueue();
  if (freq == 0)
      return;
  if (upDown_ == UP_QUEUE)
    {
       if ((rand() & (freq-1)) != 0)
         return;
        NABoolean needsError = FALSE;
        switch (qe->upState.status)
        {
        case Q_OK_MMORE:
          {
            needsError = TRUE;
            qe->upState.status = Q_SQLERROR;
            cerr << "Converting a Q_OK_MMORE to a Q_SQLERROR, from "
                 << NodeTypeToString(unblockSubtask_->getTcb()->getNodeType())
                 << "(" << unblockSubtask_->getTcb() << ")" 
                 << " to "
                 << NodeTypeToString(insertSubtask_->getTcb()->getNodeType())
                 << "(" << insertSubtask_->getTcb() << ")" 
                 << endl;
            break;
          }
        case Q_NO_DATA:
          if (!isFull())
            {
              needsError = TRUE;
              qe->upState.status = Q_SQLERROR;
              ex_queue_entry *newQNODATA = getTailEntry();
              newQNODATA->upState = qe->upState;
              newQNODATA->upState.status  = Q_NO_DATA;
              newQNODATA->getAtp()->copyAtp(qe->getAtp());
              tail_++;
              cerr << "Injecting a Q_SQLERROR before a Q_NO_DATA, from " 
                 << NodeTypeToString(unblockSubtask_->getTcb()->getNodeType())
                 << "(" << unblockSubtask_->getTcb() << ")" 
                 << " to "
                 << NodeTypeToString(insertSubtask_->getTcb()->getNodeType())
                 << "(" << insertSubtask_->getTcb() << ")" 
                 << endl;
            }
          break;
        default:
            break;
        } 
        if (needsError)
          {
            ComDiagsArea * da = qe->getDiagsArea();
            if (!da) 
              da = ComDiagsArea::allocate(insertSubtask_->getTcb()->getHeap());
            else
              da = da->copy();
            qe->setDiagsArea(da);

            *da << DgSqlCode(-EXE_ERROR_INJECTED)
                << DgString0(__FILE__)
                << DgInt0(__LINE__);
          }
    }
#endif

  return;
}
예제 #26
0
short ExIarTcb::work()
{
   // The work method does the actual extraction, selection, and projection
   // work. There are 4 possible states:
   // IAR_NOT_STARTED: This is the initial state before starting the IAR
   //                  operation. This is the state that gets set when the
   //                  TCB is built and parent queues allocated.
   // IAR_RETURNING_ROWS: In this state, the operator performs the actual
   //                  column extraction from the audit row image, and 
   //                  projects relevant columns.
   // IAR_DONE: In this state, Q_NO_DATA is returned in the upqueue to the
   //                  parent and state is reinitialized to IAR_NOT_STARTED.
   // IAR_ERROR: This is the state that is reached if an error occurs in any
   //            other state. The state is changed in this case to IAR_DONE.
  
   ex_queue_entry * pentry_down;
   ExIarPrivateState * pstate;
   ex_queue::down_request request;

   while (1) {
      if (qparent_.down->isEmpty())
         return WORK_OK;

      if (qparent_.up->isFull())
         return WORK_OK;

      pentry_down = qparent_.down->getHeadEntry();
      pstate = (ExIarPrivateState *)pentry_down->pstate;
      request = pentry_down->downState.request;

      switch (pstate->step_)
      {
         case IAR_NOT_STARTED:
         {
           if (request == ex_queue::GET_NOMORE) 
              pstate->step_ = IAR_DONE;
           else
              pstate->step_ = IAR_RETURNING_ROWS;
         }
         break;

         case IAR_RETURNING_ROWS:
         {
            if (qparent_.down->isEmpty())
               return WORK_OK; // no more requests - just return.

            if (qparent_.up->isFull())
               return WORK_OK; // parent queue is full. Just return.

            ex_queue_entry * up_entry = qparent_.up->getTailEntry();

            // Copy the input atp into the up queue atp.
            up_entry->copyAtp(pentry_down);

	    tupp returnedRow;
		
            // Allocate space to hold the projected output row to be 
            // returned.
#pragma nowarn(1506)
	    if (pool_->get_free_tuple(returnedRow, iarTdb().outputRowLen_))
#pragma warn(1506)
	      return WORK_POOL_BLOCKED; // couldn't allocate, try again later.
	    
	    up_entry->getTupp(iarTdb().criDescUp_->noTuples()-1) = returnedRow;
	    
	    tupp extractedRow;
	    
            // Allocate space to hold the extracted row.
#pragma nowarn(1506)
	    if (pool_->get_free_tuple(extractedRow, iarTdb().extractedRowLen_))
#pragma warn(1506)
	      return WORK_POOL_BLOCKED; // couldn't allocate, try again later.
	    
	    workAtp_->getTupp(2) = extractedRow;
	    
            ex_expr::exp_return_type retCode;
            if (iarTdb().getExtractExpr())
	      {
               retCode = iarTdb().getExtractExpr()->eval(pentry_down->getAtp(), 
                                                         workAtp_);
               if (retCode == ex_expr::EXPR_ERROR)
               {
                  // Set the diagnostics area in the up queue entry.
                  ComDiagsArea *upEntryDiags = up_entry->getDiagsArea();
                  ComDiagsArea *da = pentry_down->getAtp()->getDiagsArea();
                  if (!upEntryDiags)
                  {
                     upEntryDiags = 
                         ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
                     up_entry->setDiagsArea(upEntryDiags);
                  }
                  upEntryDiags->mergeAfter(*da);
                  pstate->step_ = IAR_ERROR;
                  break;
               }
            }

            // Evaluate the selection predicate, if any. 
            if (iarTdb().getScanExpr())
            {
               retCode = iarTdb().getScanExpr()->eval(pentry_down->getAtp(),
                                                      workAtp_);
               if (retCode == ex_expr::EXPR_FALSE)
               {
                  pstate->step_ = IAR_DONE;
                  break;
               }
               else
               {
                  if (retCode == ex_expr::EXPR_ERROR)
                  {
                     // Set the diagnostics area in the up queue entry.
                     ComDiagsArea *upEntryDiags = up_entry->getDiagsArea();
                     ComDiagsArea *da = pentry_down->getAtp()->getDiagsArea();
                     if (!upEntryDiags)
                     {
                        upEntryDiags =
                          ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
                        up_entry->setDiagsArea(upEntryDiags);
                     }
                     upEntryDiags->mergeAfter(*da);
                     pstate->step_ = IAR_ERROR;
                     break;
                  }
               }
            }

            // Evaluate the projection expression, if any.
            if (iarTdb().getProjExpr())
            { 
               retCode = iarTdb().getProjExpr()->eval(up_entry->getAtp(),
                                                      workAtp_);
               if (retCode == ex_expr::EXPR_ERROR)
               {
                  pstate->step_ = IAR_ERROR;
                  break;
               }
            }

            up_entry->upState.status = ex_queue::Q_OK_MMORE;
            up_entry->upState.parentIndex = 
                                         pentry_down->downState.parentIndex;
            up_entry->upState.downIndex = qparent_.down->getHeadIndex();
            pstate->matchCount_++;
            up_entry->upState.setMatchNo(pstate->matchCount_);
            qparent_.up->insert();
            pstate->step_ = IAR_DONE;
         }
         break;

         case IAR_DONE:
         {
            if (qparent_.up->isFull())
               return WORK_OK; // parent queue is full. Just return.

            ex_queue_entry * up_entry = qparent_.up->getTailEntry();
            up_entry->upState.parentIndex = pentry_down->downState.parentIndex;
            up_entry->upState.setMatchNo(pstate->matchCount_);
            up_entry->upState.status = ex_queue::Q_NO_DATA;
            qparent_.up->insert();

	    workAtp_->release();
	    
            qparent_.down->removeHead();
	    
            pstate->step_ = IAR_NOT_STARTED;
         }
         break;

         case IAR_ERROR:
         {
            if (qparent_.up->isFull())
               return WORK_OK;

            ex_queue_entry * up_entry = qparent_.up->getTailEntry();
            up_entry->upState.parentIndex = pentry_down->downState.parentIndex;
            up_entry->upState.setMatchNo(pstate->matchCount_);
            up_entry->upState.status = ex_queue::Q_SQLERROR;

            // insert into parent
            qparent_.up->insert();
            pstate->step_ = IAR_DONE;
         }
         break;
 
         default:
            ex_assert(FALSE, "Invalid step in TCB down queue");
            break;
      } 
   }

#pragma nowarn(203)
   return WORK_OK;
#pragma warn(203)
};
예제 #27
0
// print MDFWriter errors to cout
void SQLJFile::printMDFWriterErrors(char *errFileName)
{
  char args[1024], EorW[10];
  Int32  errNum;
  FILE *errFile = fopen(errFileName, "r");
  if (errFile) {
    // accommodate case of MDFWriter dumping more entries into its errFile
    // than can fit into the fixed-size diags area. Do this by feeding
    // and then dumping diags one entry at a time.
    ComDiagsArea *myDiags = ComDiagsArea::allocate(mxCUMptr->heap());
    while (fscanf(errFile, "%s %d ", EorW, &errNum) != EOF) {
      size_t sLen = 0;
      if (fgets(args, 1024, errFile) == NULL) { // fgets got EOF or an error
        args[0] = 0; // empty string
        *mxCUMptr << FAIL;
      }
      else { // fgets got something
        sLen = strlen(args);
        // chop off terminating newline
        if (args[sLen-1] == '\n') {
          args[sLen-1] = 0;
        }
        if (sLen >= 1023) { // diagnostic msg is too long
          // toss rest of line
          Int32 nxtCh;
          do {
            nxtCh = fgetc(errFile);
          } while (nxtCh != '\n' && nxtCh != EOF);
        }
      }
      if (!myDiags) { // no diags
        *mxCUMptr << FAIL;
        if (sLen >= 1023) { // diagnostic msg is too long
          cerr << "Diagnostic message is over 1023 characters long." << endl;
        }
        // echo error file entry to cerr
        cerr << EorW << " " << errNum << " " << args << endl;
      }
      else {
        if (sLen >= 1023) { // diagnostic msg is too long
          *mxCUMptr << WARNING;
          *myDiags << DgSqlCode(2237);
        }
        switch (errNum) {
        case 2224:
        case 2225:
        case 2226:
          *mxCUMptr << FAIL; 
          *myDiags << DgSqlCode(-errNum);
          break;
        case 2227:
        case 2228:
        case 2230:
          *mxCUMptr << FAIL;
          *myDiags << DgSqlCode(-errNum) << DgString0(args);
          break;
        case 2229:
          *mxCUMptr << ERROR;
          *myDiags << DgSqlCode(-errNum) << DgString0(args);
          break;
        default:
          *mxCUMptr << (EorW[0]=='E' ? ERROR :
                        (EorW[0]=='W' ? WARNING : FAIL));
          *myDiags << DgSqlCode(-2231) << DgInt0(errNum) 
                   << DgString0(EorW) << DgString1(args);
          break;
        } // end switch
        NADumpDiags(cerr, myDiags, TRUE);
        myDiags->clear();
      } // end if
    } // end while
    if (myDiags) {
      myDiags->decrRefCount();
    }
    fclose(errFile);
  }
  else {
    *mxCUMptr << FAIL << DgSqlCode(-2218) << DgString0(errFileName);
  }
  // clean up temporary file (MDFWriter errors)
  remove(errFileName);
}
예제 #28
0
void processALoadMessage(UdrGlobals *UdrGlob,
                         UdrServerReplyStream &msgStream,
                         UdrLoadMsg &request,
                         IpcEnvironment &env)
{
  const char *moduleName = "processALoadMessage";
  char errorText[MAXERRTEXT];

  ComDiagsArea *diags = ComDiagsArea::allocate(UdrGlob->getIpcHeap());

  doMessageBox(UdrGlob, TRACE_SHOW_DIALOGS,
               UdrGlob->showLoad_, moduleName);

  NABoolean showLoadLogic = (UdrGlob->verbose_ &&
                             UdrGlob->traceLevel_ >= TRACE_IPMS &&
                             UdrGlob->showLoad_);

  if (showLoadLogic)
  {
    ServerDebug("[UdrServ (%s)] Processing load request", moduleName);
  }

  // UDR_LOAD message always comes with transaction and they are out
  // side Enter Tx and Exit Tx pair. Make sure we are under correct
  // transaction.
  msgStream.activateCurrentMsgTransaction();

  //
  // Check to see if the incoming UDR handle has already been seen
  //
  NABoolean handleAlreadyExists = FALSE;
  SPInfo *sp = UdrGlob->getSPList()->spFind(request.getHandle());
  if (sp)
  {
    handleAlreadyExists = TRUE;
    if (showLoadLogic)
    {
      ServerDebug("    Duplicate handle arrived");
      ServerDebug("    SPInfoState is %s", sp->getSPInfoStateString());
    }

    if (sp->getSPInfoState() != SPInfo::UNLOADING)
    {
      //
      // An SPInfo exists but it is not one of the token instances to
      // represent an out-of-sequence LOAD/UNLOAD. This is an internal
      // error. Something has been botched in the message protocol.
      //
      char buf[100];
      convertInt64ToAscii(request.getHandle(), buf);
      *diags << DgSqlCode(-UDR_ERR_DUPLICATE_LOADS);
      *diags << DgString0(buf);
    }
    else
    {
      // The LOAD/UNLOAD requests for this handle arrived
      // out-of-sequence. Nothing to do at this point. An empty reply
      // will be generated later in this function.
    }
  }

  if (!handleAlreadyExists)
  {
    if (!UdrHandleIsValid(request.getHandle()))
    {
      *diags << DgSqlCode(-UDR_ERR_MISSING_UDRHANDLE);
      *diags << DgString0("Load Message");
    }
    else
    {
      //
      // First process the metadata in the LOAD requests and then
      // contact Language Manager to load the SP.
      //
      sp = processLoadParameters(UdrGlob, request, *diags);
      
      if (showLoadLogic)
      {
        ServerDebug("[UdrServ (%s)]  About to call LM::getRoutine",
                    moduleName);
      }
      
      if (sp == NULL)
      {
        *diags << DgSqlCode(-UDR_ERR_UNABLE_TO_ALLOCATE_MEMORY);
        *diags << DgString0("SPInfo");
      }
      else
      {
        UdrGlob->setCurrSP(sp);
        LmRoutine *lmRoutine;
        LmResult lmResult;
        LmLanguageManager *lm =
          UdrGlob->getOrCreateLM(lmResult, sp->getLanguage(), diags);
        LmHandle emitRowFuncPtr;

        if (sp->getParamStyle() == COM_STYLE_CPP_OBJ)
          emitRowFuncPtr = (LmHandle)&SpInfoEmitRowCpp;
        else
          emitRowFuncPtr = (LmHandle)&SpInfoEmitRow;
        
        if (lm)
        {
          if (sp->getParamStyle() == COM_STYLE_JAVA_OBJ ||
              sp->getParamStyle() == COM_STYLE_CPP_OBJ)
            {
              lmResult = lm->getObjRoutine(
                   request.getUDRSerInvocationInfo(),
                   request.getUDRSerInvocationInfoLen(),
                   request.getUDRSerPlanInfo(),
                   request.getUDRSerPlanInfoLen(),
                   sp->getLanguage(),
                   sp->getParamStyle(),
                   sp->getExternalName(),
                   sp->getContainerName(),
                   sp->getExternalPathName(),
                   sp->getLibrarySqlName(),
                   &lmRoutine,
                   diags);

              if (lmRoutine)
                {
                  LmRoutineCppObj *objRoutine =
                    static_cast<LmRoutineCppObj *>(lmRoutine);

                  if (sp->getParamStyle() == COM_STYLE_CPP_OBJ)
                    // set function pointers for functions provided
                    // by tdm_udrserv
                    objRoutine->setFunctionPtrs(SpInfoGetNextRow,
                                                SpInfoEmitRowCpp);

                  // add items to the UDRInvocationInfo that are not
                  // known at compile time (total # of instances is
                  // kind of known, but we want to give the executor a
                  // chance to change it)
                  lmRoutine->setRuntimeInfo(request.getParentQid(),
                                            request.getNumInstances(),
                                            request.getInstanceNum());

#ifndef NDEBUG
                  int debugLoop = 2;

                  if (objRoutine->getInvocationInfo()->getDebugFlags() &
                      tmudr::UDRInvocationInfo::DEBUG_LOAD_MSG_LOOP)
                    debugLoop = 1;
                  // go into a loop to allow the user to attach a debugger,
                  // if requested, set debugLoop = 2 in the debugger to get out
                  while (debugLoop < 2)
                    debugLoop = 1-debugLoop;
#endif

                }
            }
          else
            lmResult = lm->getRoutine(sp->getNumParameters(),
                                      sp->getLmParameters(),
                                      sp->getNumTables(),
                                      sp->getLmTables(),
                                      sp->getReturnValue(),
                                      sp->getParamStyle(),
                                      sp->getTransactionAttrs(),
                                      sp->getSQLAccessMode(),
                                      sp->getParentQid(),
                                      sp->getRequestRowSize(),
                                      sp->getReplyRowSize(),
                                      sp->getSqlName(),
                                      sp->getExternalName(),
                                      sp->getRoutineSig(),
                                      sp->getContainerName(),
                                      sp->getExternalPathName(),
                                      sp->getLibrarySqlName(),
                                      UdrGlob->getCurrentUserName(),
                                      UdrGlob->getSessionUserName(),
                                      sp->getExternalSecurity(),
                                      sp->getRoutineOwnerId(),
                                      &lmRoutine,
                                      (LmHandle)&SpInfoGetNextRow,
                                      emitRowFuncPtr,
                                      sp->getMaxNumResultSets(),
                                      diags);
        }
        
        if (lmResult == LM_OK)
        {
          if (lmRoutine == NULL)
          {
            *diags << DgSqlCode(-UDR_ERR_MISSING_LMROUTINE);
            *diags << DgString0("error: returned a null LM handle");
            *diags << DgInt1((Int32)0);
          }
          else
          {
            sp->setLMHandle(lmRoutine);

	    // Retrieve any optional data from UdrLoadMsg.
	    copyRoutineOptionalData(request, sp);

            reportLoadResults(UdrGlob, sp, lmRoutine);
            sp->setSPInfoState(SPInfo::LOADED);
          }

        } // lmResult == LM_OK

        if (showLoadLogic)
        {
          if (lmResult == LM_OK)
          {
            sprintf(errorText,
                    "[UdrServ (%.30s)]  LM::getRoutine was successful.",
                    moduleName);
          }
          else
          {
            sprintf(errorText,
                    "[UdrServ (%.30s)]  LM::getRoutine resulted in error.",
                    moduleName);
          }
          ServerDebug(errorText);
          doMessageBox(UdrGlob, TRACE_SHOW_DIALOGS,
                       UdrGlob->showMain_, errorText);
        }

        if (sp && !(sp->isLoaded()))
        {
          sp->setSPInfoState(SPInfo::LOAD_FAILED);
        }

      } // if (sp == NULL) else ...
    } // if (handle is not valid) else ...
  } // !handleAlreadyExists

  // build a reply and send it
  msgStream.clearAllObjects();

  UdrLoadReply *reply = new (UdrGlob->getIpcHeap())
    UdrLoadReply(UdrGlob->getIpcHeap());

  if (reply == NULL)
  {  // no reply buffer build...
    controlErrorReply(UdrGlob, msgStream, UDR_ERR_MESSAGE_PROCESSING,
                      INVOKE_ERR_NO_REPLY_BUFFER, NULL);
    return;
  }

  // Only return a valid UDR Handle if diagnostics are not present and
  // no LM errors occurred. We also return a valid handle if this LOAD
  // arrived out-of-sequence after the UNLOAD and no diagnostics have
  // been generated yet.
  if (diags && diags->getNumber() > 0)
  {
    reply->setHandle(INVALID_UDR_HANDLE);
  }
  else if (sp)
  {
    if (sp->isLoaded() || handleAlreadyExists)
    {
      reply->setHandle(sp->getUdrHandle());
    }
    else
    {
      reply->setHandle(INVALID_UDR_HANDLE);
    }
  }

  msgStream << *reply;

  if (diags && diags->getNumber() > 0)
  {
    msgStream << *diags;
    UdrGlob->numErrUDR_++;
    UdrGlob->numErrSP_++;
    UdrGlob->numErrLoadSP_++;
    if (showLoadLogic)
      dumpDiagnostics(diags, 2);
  }

  if (showLoadLogic)
  {
    ServerDebug("[UdrServ (%s)] About to send LOAD reply", moduleName);
  }

#ifdef NA_DEBUG_C_RUNTIME
  if (UdrGlob && UdrGlob->getJavaLM())
  {
    sleepIfPropertySet(*(UdrGlob->getJavaLM()),
                       "MXUDR_LOAD_DELAY", diags);
  }
#endif // NA_DEBUG_C_RUNTIME

  sendControlReply(UdrGlob, msgStream, sp);

  if (diags)
  {
    diags->decrRefCount();
  }

  reply->decrRefCount();

} // processALoadMessage
short ExExeUtilTcb::executeQuery(char * task, 
				 char * object,
				 char * query,
				 NABoolean displayStartTime,
				 NABoolean displayEndTime,
				 short &rc,
				 short * warning,
				 Lng32 * ec,
				 NABoolean moveErrorRow,
				 NABoolean continueOnError,
				 NABoolean monitorThis)
{
  short retcode = 0;
  char buf[BUFFER_SIZE];

  while (1)
    {
      switch (pqStep_)
	{
	case PROLOGUE_:
	  {
	    warning_ = 0;
	    startTime_ = NA_JulianTimestamp();
	    elapsedTime_ = 0;
	    if (displayStartTime)
	      {
		getStatusString(task, "Started", object, buf);
		if (moveRowToUpQueue(buf, 0, &rc))
		  return 1;
	      }

	    pqStep_ = EXECUTE_;
	    rc = WORK_RESCHEDULE_AND_RETURN;
	    return 1;
	  }
	  break;
	
	case EXECUTE_:
	  {
	    retcode = cliInterface()->fetchRowsPrologue(query,FALSE,monitorThis);
	    if (retcode < 0)
	      {
		pqStep_ = ERROR_RETURN_;
		break;
	      }
	    
	    pqStep_ = FETCH_ROW_;
	  }
	  break;
	
	case FETCH_ROW_:
	  {
	    retcode = (short)cliInterface()->fetch();
	    if (retcode < 0)
	      {
		pqStep_ = ERROR_RETURN_;
		break;
	      }
	    
	    if ((retcode > 0) &&
		(retcode != 100))
	      warning_ = retcode;

	    if ((retcode != 100) &&
		(cliInterface()->outputBuf()))
	      pqStep_ = RETURN_ROW_;
	    else
	      pqStep_ = CLOSE_;
	  }
	  break;
	
	case RETURN_ROW_:
	  {
	    char * ptr;
	    Lng32   len;
	    
	    cliInterface()->getPtrAndLen(1, ptr, len);
	    retcode = moveRowToUpQueue(ptr, len, &rc);
	    if (retcode)
	      return 1;
	    
	    pqStep_ = FETCH_ROW_;
	  }
	  break;
	
	case CLOSE_:
	  {
	    retcode = cliInterface()->fetchRowsEpilogue("");
	    if (retcode < 0)
	      {
		pqStep_ = ERROR_RETURN_;
		break;
	      }

	    pqStep_ = EPILOGUE_;
	  }
	  break;
	
	case EPILOGUE_:
	  {
            endTime_ = NA_JulianTimestamp();
            elapsedTime_ = endTime_ - startTime_;

	    if (displayEndTime)
	      {
		char timeBuf[200];
		getTimeAsString(elapsedTime_, timeBuf);
		getStatusString(task, "Ended", object, buf, timeBuf);
		if (moveRowToUpQueue(buf, 0, &rc))
		  return 1;
	      }

	    pqStep_ = ALL_DONE_;
	    rc = WORK_RESCHEDULE_AND_RETURN;
	    return 1;
	  }
	  break;
	
	case ERROR_RETURN_:
	  {
	    Lng32 sqlcode = 0;
	    char * stringParam1 = NULL;
	    Lng32   intParam1 = ComDiags_UnInitialized_Int;

	    retcode = (short)cliInterface()->retrieveSQLDiagnostics(getDiagsArea());
	    if (moveErrorRow)
	      {
		if (retcode == 0)
		  {
		    ComDiagsArea * da = getDiagsArea();
		    
		    sqlcode = (short)da->mainSQLCODE();
		    
		    ComCondition * cc;
		    if (sqlcode < 0)
		      cc = da->getErrorEntry(1);
		    else
		      cc = da->getWarningEntry(1);
		    
		    if (sqlcode < 0 && ec != NULL)
		      *ec = sqlcode;
		    
		    if (cc->getOptionalStringCharSet(0) == CharInfo::ISO88591 || cc->getOptionalStringCharSet(0) == CharInfo::UTF8)
		      stringParam1 = (char*)cc->getOptionalString(0);
		    else
		      stringParam1 = NULL;
		    intParam1    = cc->getOptionalInteger(0);
		  }
		else
		  {
		    sqlcode = retcode;
		  }
		
	 Lng32 errorBufLen = 
		  200 + (stringParam1 ? strlen(stringParam1) : 0);
		
		char * errorBuf = new(getHeap()) char[errorBufLen];
		
		str_sprintf(errorBuf, "%d", sqlcode);
		if (stringParam1)
		  str_sprintf(&errorBuf[strlen(errorBuf)], ", %s", stringParam1);
		if (intParam1 != ComDiags_UnInitialized_Int)
		  str_sprintf(&errorBuf[strlen(errorBuf)], ", %d", intParam1);
		
		char * outBuf = new(getHeap()) char[errorBufLen+400];
		getStatusString(task, "Error", NULL, outBuf,
				NULL, NULL,
				errorBuf);
		
		NADELETEBASIC(errorBuf, getHeap());
		
		if ((moveErrorRow) &&
		    (moveRowToUpQueue(outBuf, 0, &rc)))
		  {
		    NADELETEBASIC(outBuf, getHeap());
		    
		    return 1;
		  }

		NADELETEBASIC(outBuf, getHeap());
	      }

	    // close cursor, etc. Ignore errors.
	    cliInterface()->fetchRowsEpilogue("");

	    if (continueOnError)
	      {
		pqStep_ = ALL_DONE_;

		rc = WORK_RESCHEDULE_AND_RETURN;
		return 1;
	      }
	    else
	      {
		pqStep_ = PROLOGUE_;
		return -1;
	      }
	  }
	  break;

	case ALL_DONE_:
	  {
	    pqStep_ = PROLOGUE_;

	    if (warning)
	      *warning = warning_;

	    return 0;
	  }
	  break;
	
	}
    }
}
예제 #30
0
void EspNewIncomingConnectionStream::actOnReceive(IpcConnection *connection)
{
  // check for OS errors
  if (getState() == ERROR_STATE)
  {
    ex_assert(FALSE,"Error while receiving first message from client");
  }

  // check for protocol errors
  bool willPassTheAssertion = 
             (getType() == IPC_MSG_SQLESP_DATA_REQUEST OR
              getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND
              getVersion() == CurrEspRequestMessageVersion AND
              moreObjects();
  if (!willPassTheAssertion)
  {
    char *doCatchBugCRx = getenv("ESP_BUGCATCHER_CR_NONUMBER");
    if (!doCatchBugCRx ||
        *doCatchBugCRx != '0')
    {
      connection->dumpAndStopOtherEnd(true, false);
      environment_->getControlConnection()->
        castToGuaReceiveControlConnection()->
        getConnection()->dumpAndStopOtherEnd(true, false);
    }
  }

  ex_assert((getType() == IPC_MSG_SQLESP_DATA_REQUEST OR
             getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND
	    getVersion() == CurrEspRequestMessageVersion AND
	    moreObjects(),
	    "Invalid first message from client");

  // take a look at the type of the first object in the message
  IpcMessageObjType nextObjType = getNextObjType();
  switch (nextObjType)
  {
    case ESP_OPEN_HDR:
    case ESP_LATE_CANCEL_HDR:
      {
        ExFragKey key;
        Lng32 remoteInstNum;
        NABoolean isParallelExtract = false; 

        // peek at the message header to see for whom it is
        if (nextObjType == ESP_OPEN_HDR)
        {
          ExEspOpenReqHeader reqHdr((NAMemory *) NULL);
	   
	  *this >> reqHdr;
	  key = reqHdr.key_;
	  remoteInstNum = reqHdr.myInstanceNum_;
	  if (reqHdr.getOpenType() == ExEspOpenReqHeader::PARALLEL_EXTRACT) 
          {
            isParallelExtract = true;
	  }
	}
        else
	{
          // note that the late cancel request may or may not
	  // arrive as the first request (only in the former case
	  // will we reach here)
	  ExEspLateCancelReqHeader reqHdr((NAMemory *) NULL);
	   
	  *this >> reqHdr;
	  key = reqHdr.key_;
	  remoteInstNum = reqHdr.myInstanceNum_;
	}

        if (!isParallelExtract) 
        {
          ExFragInstanceHandle handle =
	    espFragInstanceDir_->findHandle(key);

	  if (handle != NullFragInstanceHandle)
	  {
            // the send bottom node # myInstanceNum of this downloaded fragment
            // is the true recipient of this open request
            ex_split_bottom_tcb * receivingTcb =
              espFragInstanceDir_->getTopTcb(handle);
            ex_send_bottom_tcb *receivingSendTcb =
              receivingTcb->getSendNode(remoteInstNum);

            // Check the connection for a co-located client, and if so,
            // tell the split bottom, because it may prefer this send 
            // bottom when using skew buster uniform distribution.
            if (espFragInstanceDir_->
                  getEnvironment()->
                  getMyOwnProcessId(IPC_DOM_GUA_PHANDLE).match(
                    connection->getOtherEnd().getNodeName(),
                    connection->getOtherEnd().getCpuNum()))
              receivingTcb->setLocalSendBottom(remoteInstNum);

            // Portability note for the code above: we pass IPC_DOM_GUA_PHANDLE
            // for IpcEnvironment::getMyOwnProcessId, even though that method
            // can be called with the default param (IpcNetworkDomain 
            // IPC_DOM_INVALID).  In fact it would  probably be better 
            // to call the object without specifying the IpcNetworkDomain so
            // that it can decide for itself what domain it is using.
            // But there is a problem with the Windows implementation
            // of IpcEnvironment::getMyOwnProcessId, it seems to assume
            // that its domain is IPC_DOM_INTERNET and so this will 
            // cause the botch of an assertion that its control connection 
            // (which is type EspGuaControlConnection) can be cast to a 
            // SockControlConnection.  When this problem is fixed, the 
            // IPC_DOM_GUA_PHANDLE param above can be removed.  Also,
            // when this code is ported to run it a domain other than
            // "guardian", it will be necessary to fix this and to
            // fix IpcEnvironment::getMyOwnProcessId to work properly on
            // windows.

            receivingSendTcb->setClient(connection);
            receivingSendTcb->routeMsg(*this);
          }
	  else
	  {
            connection->dumpAndStopOtherEnd(true, false);
	    ex_assert(FALSE,"entry not found, set diagnostics area and reply");
	  }

        } // normal case, not parallel extract

        else 
        {
          // The OPEN request is from a parallel extract consumer. The
          // incoming request contains a user ID which we will compare
          // against the current user ID for this ESP.

          // NOTE: The user ID for the extract security check is
          // currently sent and compared as a C string. On Linux it is
          // possible to send and compare integers which would lead to
          // simpler code. The code to send/compare strings is still
          // used because it works on all platforms.

          char errorStr[150];

	  // check if next msg is of securityInfo type. 
          ex_assert(moreObjects(), "expected object not received");
          ex_assert(getNextObjType() == ESP_SECURITY_INFO,
	            "received message for unknown message type");
          
	  // unpack security info
	  ExMsgSecurityInfo secInfo(environment_->getHeap());
	  *this >> secInfo;

          // Get the auth ID of this ESP in text form and compare it
          // to the auth ID that arrived in the message. Skip this
          // step in the debug build if an environment variable is
          // set.
          NABoolean doAuthIdCheck = TRUE;
          Int32 status = 0;
#ifdef _DEBUG
          const char *envvar = getenv("NO_EXTRACT_AUTHID_CHECK");
          if (envvar && envvar[0])
            doAuthIdCheck = FALSE;
#endif
          if (doAuthIdCheck)
          {
            // Get user ID from ExMsgSecurityInfo -> (secUserID)
            // the user ID is the integer value made into a string
            // Convert it back into its integer value
            short userIDLen = (short) str_len(secInfo.getAuthID());
            Int32 secUserID = str_atoi(secInfo.getAuthID(), userIDLen);

            // Get the current user ID
            Int32 curUserID = ComUser::getSessionUser(); 

            // Report an error if the user ID is not valid
            if (curUserID == NA_UserIdDefault || secUserID == NA_UserIdDefault)
            {
              str_cpy_c(errorStr,
                        "Producer ESP could not authenticate the consumer, "
                        "no valid current user.");
              status = -1;
            }

            // Make sure user id passed in ExMsgSecurityInfo matches
            // the user id associated with the current session

#if defined(_DEBUG)
            NABoolean doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE);
            if (doDebug)
              printf("[DBUSER:%d] ESP extract user ID: "
                     "local [%d], msg [%d]\n",
                     (int) getpid(), curUserID, secUserID);
#endif

              // Compare user ID, Report an error, if comparison fails
              if (curUserID != secUserID)
              {
                str_cpy_c(errorStr,
                          "Producer ESP could not authenticate the consumer, "
                          "user named passed in ExMsgSecurityInfo is not the "
                          "current user");
                status = -1;
              }

          } // if (doAuthIdCheck)
		   
          // get the split bottom TCB that matches the securityKey
          ex_split_bottom_tcb *receivingTcb = NULL;
          if (status == 0) 
          {
            receivingTcb = espFragInstanceDir_->getExtractTop(secInfo.getSecurityKey());
            if (receivingTcb == NULL) 
            {
              str_cpy_c(errorStr, "Producer ESP could not locate extract node");
              status = -1;
            }
          }

	  // get the sendBottom TCB if not already connected to a client
	  ex_send_bottom_tcb *receivingSendTcb = NULL;
	  if (status == 0)
	  {
	    receivingSendTcb = receivingTcb->getConsumerSendBottom();
	    if (receivingSendTcb == NULL) 
	    {
	      str_cpy_c(errorStr, "Producer ESP already connected to a client");
	      status = -1;
	    }
	  }

          // send the error message to the consumer 
	  if (status != 0) 
	  {
            clearAllObjects();
            setType(IPC_MSG_SQLESP_DATA_REPLY);

            NAMemory *heap = environment_->getHeap();

	    IpcMessageObj* baseObj =
	      new(heap)IpcMessageObj(IPC_SQL_DIAG_AREA, CurrEspReplyMessageVersion);
	    *this << *baseObj;

	    // prepare proper error message
	    char phandle[100];
	    MyGuaProcessHandle myHandle;
            myHandle.toAscii(phandle, 100);

	    ComDiagsArea *diags = ComDiagsArea::allocate(heap);
            *diags << DgSqlCode(-EXE_PARALLEL_EXTRACT_OPEN_ERROR)
                   << DgString0(phandle)
                   << DgString1(errorStr);
	    *this  << *diags;

	    diags->decrRefCount();

            send(TRUE /* TRUE indicates waited */);
          }

          // if everything okay, then make the connection
	  if (status == 0) 
          {
            receivingSendTcb->setClient(connection);
            receivingSendTcb->routeMsg(*this);
          }
        } // parallel extract case
      } // open or cancel header