blob: fed1674e26806e9e1855c5cbac6bafaf24e18a86 [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 @@@
**********************************************************************/
#ifndef ExCompoundStmt_h
#define ExCompoundStmt_h
/* -*-C++-*-
******************************************************************************
*
* File: ExCompoundStmt.h
* Description: 3GL compound statement (CS) operator.
*
* Created: 4/1/98
* Language: C++
*
*
*
******************************************************************************
*/
#include "ComTdbCompoundStmt.h"
class ex_tcb;
// ExCatpoundStmt implements "catpound statement" semantics. That is, given
// exec sql begin
// select c1 into :h1 from t1;
// select c2 into :h2 from t2;
// end;
// it produces a single row result set like this
// c1 c2
// --- ---
// :h1 :h2
// In other words, it restricts any contained selects to be at most single-
// row selects and collapses any single-row result sets into one catenated
// result set. The "catpound statement" result schema is the concatenation
// of the columns of any contained select statemetns: columns of result set1
// || columns of result set2 || columns of result set3 ... (see ~/generator/
// GenRel3GL.cpp for the "catpound statement" result row layout).
// A "catpound statement" implementation of the SQL compound statement is
// a correct implementation provided: 1) the single-row-selects constraint
// is enforced, and 2) the "catpound" result schema is not exposed to the
// user (eg, it must not show up in sqlci output!).
// True SQL compound statements do not change the logical result of their
// component statements. Thus, in the above example, the true SQL compound
// statement output should look like this
// c1
// ---
// :h1
//
// c2
// ---
// :h2
// In other words, the output of executing a compound statement is exactly
// the same as the output of executing the contained statements one after
// another in (textual) sequential order.
// Therefore, both (the current) "catpound" and (a future true SQL
// implementation of) compound statement operators must preserve this
// logical sequential execution order. This is an important correctness
// criteria. It means that even a parallel implementation of compound
// statement must preserve logical execution order of the contained SQL
// statements. In terms of the SQLMX pipelined parallel execution engine,
// it may mean that the result sets must be delivered in order in the master
// executor root node's up queue. An aggressively pipelined implementation
// of a compound statement operator may execute its left and right children
// in any order but it must deposit the left child's result in the parent's
// up queue first before it can deliver any results from the right child.
// The sequential delivery of result sets to the SQL application program
// is essential to the correct behavior of CLI result set processing calls.
// The prototype implementation of the catpoundstmt operator was patterned
// after the nested loop join (NLJ) operator: ex_onlj.{h,cpp}. But, NLJ is
// a lot more complicated in its bookkeeping because of the need to match
// left and right join columns, the handling of nulls, no-matches, etc.
// As a result, this catpoundstmt operator frequently crashed with orphaned
// queue entries.
// A catpoundstmt operator should behave more like the ordered union (OU)
// operator that was introduced to do index maintenance
// where two internally generated SQL statements (a delete and an insert)
// must execute one after another. But, OU also inherits some complicated
// whichSide generic union workUp logic that tries to parallelize (ie,
// non-deterministically interleave) delivery of left and right child
// results to the parent up-queue. As described above, correct CLI result
// set processing demands sequential in-order delivery of result sets.
// (It is conceivable that a future aggressively parallel compoundstmt
// operator may temporarily interleave up-queue processing, but it must
// balance this gain with the penalty of the bookkeeping needed to allow
// it to eventually deliver result sets in textual sequential order to the
// SQL application). In this initial implementation, we avoid inheriting
// the complicated OU whichSide workUp logic.
// In addition, the catpoundstmt operator must also deliver and flow any
// tuple values from the left to the right child just like NLJ but without
// the complicated matching and null-handling. This left-to-right tuple
// flow is needed to support catpound semantics (ie, catpound result row
// layout) and the data flow of any assignment statements.
// So, in summary, the catpoundstmt operator executes the left child first;
// flows any tuple values from the left to the right child; starts the
// right child only after the left child is done; delivers any tuple values
// from the right child's up-queue to the parent's up-queue. If right child
// has no data but left child has some, it delivers the left's data result.
// If left has no data but right has some, it delivers the right's data. If
// both left and right have data (OK_MMORE) entries, it delivers the right's
// up-queue entry because the catpoundstmt row layout means it has both left
// and right tupps catenated together and the left-to-right data flow means
// those left tupps have the left's OK_MMORE data. It also enforces the
// catpoundstmt at-most-one-row-result constraint. If either left or right
// child has more than one OK_MMORE entry, it deposits a Q_SQLERROR entry
// in the parent's up-queue and does a cancel: flushes all OK_MMORE until
// a Q_NO_DATA. Thus, the 2nd child will not be executed if the 1st child
// had any error.
// It may seem that this catpoundstmt implementation may degrade in
// performance with bigger catpoundstmts (ones that contain many component
// statements) because of the need to flow data: left-to-right-to-parent.
// But, on second thought, it is probably one of the most (protocol-wise)
// efficient implementation of at-most-one-row-per-select compound
// statements. In terms of CLI calls, sqlc will translate any (size-n)
// compound statement
// exec sql begin <stmt1>; <stmt2>; ... <stmtn>; end;
// into just one pair of CLI calls
// { ... SQL_EXEC_ExecClose(...) ... SQL_EXEC_FetchClose(...) ... }
// That is, a single Fetch() call fetches all the output host vars of all
// the component statements.
// Even in the executor, the left-to-right-to-parent data flow is done
// by filling-in tupps which are pointer (not data) copies. The real data
// copies occur at process (fragment) boundaries. The number of process
// boundaries (and data copies) is probably the same in both catpoundstmt
// and compoundstmt cases.
// -----------------------------------------------------------------------
// ExCatpoundStmtTdb
// -----------------------------------------------------------------------
class ExCatpoundStmtTdb : public ComTdbCompoundStmt
{
public:
// ---------------------------------------------------------------------
// Constructor is only called to instantiate an object used for
// retrieval of the virtual table function pointer of the class while
// unpacking. An empty constructor is enough.
// ---------------------------------------------------------------------
NA_EIDPROC ExCatpoundStmtTdb()
{}
NA_EIDPROC virtual ~ExCatpoundStmtTdb()
{}
// ---------------------------------------------------------------------
// Build a TCB for this TDB. Redefined in the Executor project.
// ---------------------------------------------------------------------
NA_EIDPROC virtual ex_tcb *build(ex_globals *globals);
private:
// ---------------------------------------------------------------------
// !!!!!!! IMPORTANT -- NO DATA MEMBERS ALLOWED IN EXECUTOR TDB !!!!!!!!
// *********************************************************************
// The Executor TDB's are only used for the sole purpose of providing a
// way to supplement the Compiler TDB's (in comexe) with methods whose
// implementation depends on Executor objects. This is done so as to
// decouple the Compiler from linking in Executor objects unnecessarily.
//
// When a Compiler generated TDB arrives at the Executor, the same data
// image is "cast" as an Executor TDB after unpacking. Therefore, it is
// a requirement that a Compiler TDB has the same object layout as its
// corresponding Executor TDB. As a result of this, all Executor TDBs
// must have absolutely NO data members, but only member functions. So,
// if you reach here with an intention to add data members to a TDB, ask
// yourself two questions:
//
// 1. Are those data members Compiler-generated?
// If yes, put them in the ComTdbCompounStmt instead.
// If no, they should probably belong to someplace else (like TCB).
//
// 2. Are the classes those data members belong defined in the executor
// project?
// If your answer to both questions is yes, you might need to move
// the classes to the comexe project.
// ---------------------------------------------------------------------
};
//////////////////////////////////////////////////////////////////////////////
// CatpoundStmt TCB class.
//////////////////////////////////////////////////////////////////////////////
class ExCatpoundStmtTcb : public ex_tcb
{
friend class ExCatpoundStmtTdb;
friend class ExCatpoundStmtPrivateState;
public:
// Standard TCB methods.
NA_EIDPROC
ExCatpoundStmtTcb(const ExCatpoundStmtTdb &tdb,
const ex_tcb &left,
const ex_tcb &right,
ex_globals *glob);
NA_EIDPROC
~ExCatpoundStmtTcb();
NA_EIDPROC
void freeResources() {}
NA_EIDPROC
void registerSubtasks();
NA_EIDPROC
virtual const ex_tcb* getChild(Int32 pos) const;
NA_EIDPROC
virtual Int32 numChildren() const { return 2; }
NA_EIDPROC
ExWorkProcRetcode work();
private:
// CS TCB specific methods.
NA_EIDPROC
ex_queue_pair getParentQueue() const { return qparent_; }
NA_EIDPROC
ExWorkProcRetcode workDownLeft();
NA_EIDPROC
ExWorkProcRetcode workLeft2Right();
NA_EIDPROC
ExWorkProcRetcode workUp();
NA_EIDPROC
ExWorkProcRetcode workCancel();
NA_EIDPROC
static ExWorkProcRetcode sWorkDownLeft(ex_tcb *tcb)
{ return ((ExCatpoundStmtTcb *) tcb)->workDownLeft(); }
NA_EIDPROC
static ExWorkProcRetcode sWorkLeft2Right(ex_tcb *tcb)
{ return ((ExCatpoundStmtTcb *) tcb)->workLeft2Right(); }
NA_EIDPROC
static ExWorkProcRetcode sWorkUp(ex_tcb *tcb)
{ return ((ExCatpoundStmtTcb *) tcb)->workUp(); }
NA_EIDPROC
static ExWorkProcRetcode sWorkCancel(ex_tcb *tcb)
{ return ((ExCatpoundStmtTcb *) tcb)->workCancel(); }
NA_EIDPROC
void startLeftChild();
NA_EIDPROC
void flowLeft2Right(ex_queue_entry *lentry);
NA_EIDPROC
void flowParent2Right(queue_index pindex);
NA_EIDPROC
void passChildReplyUp(ex_queue_entry *centry);
NA_EIDPROC
void processError(atp_struct *atp, ComDiagsArea *da);
NA_EIDPROC
void processCardinalityError(ex_queue_entry *centry);
NA_EIDPROC
void processEODErrorOrWarning(NABoolean isWarning);
NA_EIDPROC
inline ExCatpoundStmtTdb & csTdb() const
{ return (ExCatpoundStmtTdb &) tdb; }
NA_EIDPROC
inline NABoolean expectingRightRows() const
{ return csTdb().expectingRightRows(); }
NA_EIDPROC
inline NABoolean expectingLeftRows() const
{ return csTdb().expectingLeftRows(); }
NA_EIDPROC
inline NABoolean afterUpdate() const
{ return csTdb().afterUpdate(); }
private:
// CS TCB specific attributes.
enum CSState {
CS_EMPTY, // initial state
CS_STARTED, // we began execution
CS_NOT_EMPTY, // child has non-EOD row
CS_ERROR, // encountered an error
CS_DONE, // is done
CS_CANCELLED // request cancelled
};
const ex_tcb *tcbLeft_; // TCB for left child.
const ex_tcb *tcbRight_; // TCB for right child.
ex_queue_pair qparent_; // Queue for parent communication.
ex_queue_pair qleft_; // Queue for left child communication.
ex_queue_pair qright_; // Queue for right child communication.
queue_index parent2leftx_; // index of parent down queue entry being
// processed by left child
queue_index leftupx_; // left child's up queue index
};
//////////////////////////////////////////////////////////////////////////////
// CatpoundStmtPrivateState class.
//////////////////////////////////////////////////////////////////////////////
class ExCatpoundStmtPrivateState : public ex_tcb_private_state
{
friend class ExCatpoundStmtTcb;
public:
// Standard private state methods.
NA_EIDPROC
ExCatpoundStmtPrivateState(const ExCatpoundStmtTcb *tcb)
{ init(); }
NA_EIDPROC
~ExCatpoundStmtPrivateState(){}
NA_EIDPROC
ex_tcb_private_state * allocate_new(const ex_tcb *tcb);
private:
NA_EIDPROC
void init();
private:
// CS Private state attributes.
Int64 leftrows_; // Number of left tuples.
Int64 rightrows_; // Number of right tuples.
ExCatpoundStmtTcb::CSState leftstate_;
ExCatpoundStmtTcb::CSState rightstate_;
};
#endif // ExCompoundStmt_h