blob: cb19546d61170bef7fc889b029236cccf27fcd56 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: UdrResultSet.h
* Description: This file contains UdrResultSet class and
* TmpBuffer class definitions.
* Created: 10/20/2005
* Language: C++
**
*****************************************************************************
*/
#ifndef UDRRESULTSET_H
#define UDRRESULTSET_H
#include "udrdefs.h"
#include "NAType.h"
#include "LmResultSet.h"
#include "UdrExeIpc.h"
#include "ComSmallDefs.h"
#include "QueueIndex.h"
#include "udrglobals.h"
#include "LmParameter.h"
// forward references
class SPInfo;
class UdrGlobals;
// The number of different descriptor info that we are interested in
// for each column to generate Proxy Syntax. Right now we are interested in
// SQLDESC_CATALOG_NAME, SQLDESC_SCHEMA_NAME, SQLDESC_TABLE_NAME,
// SQLDESC_NAME, SQLDESC_TEXT_FORMAT, SQLDESC_HEADING, SQLDESC_NULLABLE
const Int32 NUMDESC_ITEMS = 7;
//////////////////////////////////////////////////////////////////////////
//
// TmpBuffer: This class manages the temporary location that's needed
// for UdrResultSet during row fetch from CLI.
// This class keeps track of total number of rows in the buffer and
// the number that needs to be provided to the caller. This class
// does not provide interface to read previous rows that were read.
// This class also contains the diagnostic conditions related to the
// data rows.
//
//////////////////////////////////////////////////////////////////////////
class TmpBuffer
{
public:
TmpBuffer(ComUInt32 size, ComUInt32 rowSize, NAMemory *heap)
: heap_(heap),
size_(size),
exeRowSize_(rowSize),
// When we fetch from the local CLI, we need a row size that is
// a multiple of 2. This is explained in commentary below.
fetchRowSize_(rowSize + (rowSize % 2)),
numRows_(0),
index_(0)
{
// Here's why our CLI fetch size must be even. It's a workaround
// to a quirk in the CLI. The quirky behavior only happens for
// rows with VARCHAR columns but we can use the workaround for all
// rows.
//
// First note that we use quad fields to do rowset fetching
// from the CLI (see UdrResultSet::setupQuadFields() for more info
// on our use of quad fields). The "layout" values in the quad
// fields structs are supposed to be the length of the entire
// row. The CLI uses these layout values to compute the address
// offset between a given column in two consecutive rows. For
// example, if we want column 1 in row 1 and column 1 in row 2 to
// be separated by N bytes, then we need layout values of N.
//
// For a VARCHAR column if the layout is not even, the CLI will
// "add 1" to the layout when computing these offsets. This is not
// what we want. To avoid the "add 1" quirk we simply never give
// the CLI an odd value in the layout fields. The "add 1" quirk is
// in Descriptor::getVarItem() and was supposed to be a fix for
// COBOL programs only, but is taking effect for all programs.
if (size_ < fetchRowSize_)
size_ = fetchRowSize_;
// Because of the way we setup quadfields, it is possible to overwrite
// the bytes beyond the allocated bytes if we happen to fetch rows full
// of the buffer. So we actually allocate space for one extra row beyond
// size_ bytes. Probably rowwise rowsets will not have this problem and
// should also yield better performance.
ComUInt32 nBytes = size_ + fetchRowSize_;
buffer_ = new(heap) char[nBytes];
memset(buffer_, 0, nBytes);
cliDiags_ = ComDiagsArea::allocate(heap_);
}
~TmpBuffer()
{
NADELETEBASIC(buffer_, heap_);
cliDiags_->decrRefCount();
}
// Accessors
ComUInt32 getSize() const { return size_; }
ComUInt32 getExeRowSize() const { return exeRowSize_; }
ComUInt32 getFetchRowSize() const { return fetchRowSize_; }
ComUInt32 getNumRows() const { return numRows_; }
ComUInt32 getIndex() const { return index_; }
char *getBufferPtr() const { return buffer_; }
ComDiagsArea *getDiags() const { return cliDiags_; }
ComUInt32 getNumRowsPerFetch() const { return size_ / fetchRowSize_; }
ComUInt32 getNumRowsToCopy() const { return numRows_ - index_; }
NABoolean moreRowsToCopy() const
{
UDR_ASSERT(index_ <= numRows_, "Wrong index_ value in TmpBuffer.");
return numRows_ != index_;
}
char *getNextRow(ComDiagsArea* &rowDiags,
NABoolean singleRowFetchEnabled = FALSE);
// Mutators
void setNumRows(ComUInt32 numRows) { numRows_ = numRows; }
private:
NAMemory *heap_; // Heap where buffer_ is allocated
char *buffer_; // Place where CLI rows are copied temporarily
ComUInt32 size_; // Buffer size
ComUInt32 exeRowSize_; // Row size returned to executor
ComUInt32 fetchRowSize_; // Row size fetched from the CLI
ComUInt32 numRows_; // Number of rows in this buffer
ComUInt32 index_; // Index of first row that was not copied from
// this buffer.
ComDiagsArea *cliDiags_; // CLI diags corresponding to the rows in this
// buffer
};
//////////////////////////////////////////////////////////////////////////
//
// UdrResultSet: A representation of Result Set in UDR Server layer.
//
//////////////////////////////////////////////////////////////////////////
class UdrResultSet : public NABasicObject
{
public:
enum RSState
{
RS_INITIATED = 1, // RS initialized after UDR invoke.
// The column desc is not set yet when RS is in
// this state.
RS_REINITIATED, // RS re-initialized.
// Column desc is set and may be used for fetches
// depending on the next message from master.
RS_LOADED, // Column desc populated
RS_UNLOADED, // Column desc is destroyed
RS_FETCH, // Rows being fetched (by either
// RS INVOKE or CONTINUE requests)
RS_FETCH_COMPLETE, // FETCH is compete
RS_EARLY_CLOSE, // An RS CLOSE request arrived before
// EOD was returned
RS_CLOSED // RS closed
};
// Constructor to create UdrResultSet objects during UDR_INVOKE
// phase.
UdrResultSet(SPInfo *spInfo, LmResultSet *lmRS, ComDiagsArea &d);
// Constructor that uses SQLSTMT_ID object directly. This constructor
// will be used when JDBC is not available on the platform. In this case,
// SPJ method may not be able to return actual result sets
// and LM will not create LmResultSet objects. Instead the callers create
// CLI statements directly.
UdrResultSet(SPInfo *spInfo, SQLSTMT_ID *stmt_id, ComDiagsArea &d);
~UdrResultSet();
// Accessors
SPInfo *getSPInfo() const { return spInfo_; }
RSState getState() const { return state_; }
const char * stateString();
NABoolean isInited() const { return state_ == RS_INITIATED; }
NABoolean isReInited() const { return state_ == RS_REINITIATED; }
NABoolean isLoaded() const { return state_ == RS_LOADED; }
NABoolean isUnloaded() const { return state_ == RS_UNLOADED; }
NABoolean isFetchStarted() const { return state_ == RS_FETCH; }
NABoolean isFetchComplete() const { return state_ == RS_FETCH_COMPLETE; }
NABoolean isClosed() const { return state_ == RS_CLOSED; }
NABoolean isEarlyClose() const { return state_ == RS_EARLY_CLOSE; }
RSHandle getRSHandle() const { return rsHandle_; }
const char *getProxySyntax() const { return proxySyntax_->data(); }
const LmResultSet *getLmResultSet() const { return lmResultSet_; }
ComUInt32 getContextHandle() const
{ return lmResultSet_ ? lmResultSet_->getCtxHandle() : 0; }
SQLSTMT_ID *getStatementHandle() const { return stmt_id_; }
ComUInt32 getExeRowSize() const { return exeRowSize_; }
ComUInt32 getBufferSize() const { return bufferSize_; }
// mutators
void setState(RSState state) { state_ = state; }
// Reinitialize the object. columnDesc_ will not be changed.
Int32 reInit(LmResultSet *lmRS, ComDiagsArea &d, SQLSTMT_ID *stmt_id=NULL);
// Prepare for reinvoke
// Deallocates and run cleanup methods on the non-reusable fields
void prepareForReinvoke();
// Load method.
// A 'load' on UdrResultSet refers to setting the columnDesc_ field
NABoolean load(RSHandle handle,
ComUInt32 numRSCols,
ComUInt32 rowSize,
ComUInt32 bufferSize,
UdrParameterInfo *columnDesc,
ComDiagsArea &d);
// Fetch methods
Lng32 fetchRows(UdrGlobals *udrGlob,
SqlBuffer *request,
SqlBuffer *reply,
ComDiagsArea &d,
NAList<ComDiagsArea*> *rowDiagsList);
void fetchRowsFromCLI(UdrGlobals *udrGlob,
SqlBuffer *reply,
ComUInt32 &numBufferedRows,
ComDiagsArea &d,
NAList<ComDiagsArea*> *rowDiagsList);
void fetchRowsFromJDBC(UdrGlobals *udrGlob,
SqlBuffer *reply,
ComUInt32 &numBufferedRows,
NABoolean &eofEncountered,
ComDiagsArea &d,
NAList<ComDiagsArea*> *rowDiagsList);
// Unload Result Set. This destroys the column desc. Executor has
// to send an RS_LOAD message, if it wants to use this RS
void unload();
// Close Result Set. After closing an RS, the same RS can be
// reopened by UDR INVOKE.
void close(ComDiagsArea *diags);
// This method can be called when an RS CLOSE request arrives. If
// the current state is not FETCH then this is a no-op. In the FETCH
// state, this method transitions the instance to the EARLY_CLOSE
// state. A subsequent RS CONTINUE request returns EOD to the
// executor and transitions to the CLOSE state.
void processRSClose(ComDiagsArea *diags);
private:
// Deallocates the fields that are generated by Udr Server
// This method is called from desstructor and also during preparation
// for reinvocation
void deallocateUDRGeneratedFields();
// Deallocates the fields that are downloaded from Executor. This
// method is called during destruction and unload processing.
void deallocateExeGeneratedFields();
// Makes a copy of SQLSTMT_ID struct pointed to by stmt_id. If
// resetStmtInfo is TRUE and the name mode is not stmt_handle, then
// the stmt_handle field is set to zero. This breaks any association
// with an existing StatementInfo structure inside the CLI.
SQLSTMT_ID *copyStatementID(SQLSTMT_ID *stmt_id,
NABoolean resetStmtInfo = TRUE);
// Context setting methods
Int32 setContext(SQLCTX_HANDLE &oldCtx, ComDiagsArea &d);
Int32 resetContext(SQLCTX_HANDLE ctxHandle, ComDiagsArea &d);
// Populates proxySyntax_ field
Int32 generateProxySyntax(ComDiagsArea &d);
// Allocates and populates rsColumnDesc_ & rsColDescForLM_ fields
void populateColumnDesc(UdrParameterInfo *paramInfo);
// Dealloactes rsColumnDesc_ field
void deallocateColumnDesc();
// Sets up Quad fields for CLI rowset fetching
NABoolean setupQuadFields(ComDiagsArea &d);
// Methods that copy rows into SqlBuffer
void copyRowsIntoSqlBuffer(SqlBuffer *replyBuffer,
queue_index queueIndex,
ComUInt32 &numRowsCopied,
NAList<ComDiagsArea*> *rowDiagsList);
NABoolean copyErrorRowIntoSqlBuffer(SqlBuffer *replyBuffer,
queue_index queueIndex,
ComDiagsArea &diags);
NABoolean copyEODRowIntoSqlBuffer(SqlBuffer *replyBuffer,
queue_index queueIndex);
char *fixDataRow(char *rowPtr, ComDiagsArea *rowDiags);
// The following information travels from executor
RSHandle rsHandle_; // RS Handle
UdrParameterInfo *rsColumnDesc_; // Column descriptions
ComUInt32 numColumns_; // number of columns in this RS
ComUInt32 exeRowSize_; // Row size for rows returned to executor
ComUInt32 bufferSize_; // SqlBuffer Size
// The following information is computed by UDR server
SPInfo *spInfo_; // Owning SPInfo
RSState state_; // current state
LmResultSet *lmResultSet_; // LmResultSet
NAString *proxySyntax_; // proxy syntax for this RS
// The following information is generated and managed by
// UDR server during proxy syntax creation and also for row fetching.
ComUInt32 rowsToFetchFromJDBC_; // Number of rows from JDBC
SQLSTMT_ID *stmt_id_; // Used for producing proxy syntax and
// CLI rowset fetching
SQLDESC_ID *output_desc_; // Used for producing proxy syntax and
// CLI rowset fetching
SQLCLI_QUAD_FIELDS *quad_fields_; // Used for CLI rowset fetching
queue_index parentQueueIndex_; // Queue index to be used by RS rows
// This index is same as the index seen
// in down queue.
NABoolean needToCopyErrorRow_; // Error during fetch.
NABoolean needToCopyEODRow_; // EOD reached.
NABoolean singleRowFetchEnabled_; // Fetch a single row at a time, useful
// for debugging
LmParameter *rsColDescForLM_; // Col desc for LM use
TmpBuffer *tmpBuffer_; // Place for temporary storage
};
#endif