1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // CegoProcBlock.cc
4 // ----------------
5 // Cego proc block class implementation
6 //
7 // Design and Implementation by Bjoern Lemke
8 //
9 // (C)opyright 2000-2019 Bjoern Lemke
10 //
11 // IMPLEMENTATION MODULE
12 //
13 // Class: CegoProcBlock
14 //
15 // Description: Stored procedure block container class
16 //
17 // Status: CLEAN
18 //
19 ///////////////////////////////////////////////////////////////////////////////
20 
21 // CEGO INCLUDES
22 #include "CegoProcBlock.h"
23 #include "CegoSelect.h"
24 #include "CegoProcException.h"
25 
26 #include "CegoDatabaseFormater.h"
27 
CegoProcBlock(CegoProcBlock * pParentBlock)28 CegoProcBlock::CegoProcBlock(CegoProcBlock *pParentBlock)
29 {
30     _pParentBlock = pParentBlock;
31     _pTriggerValueList = 0;
32 }
33 
~CegoProcBlock()34 CegoProcBlock::~CegoProcBlock()
35 {
36     CegoProcStmt **pStmt = _stmtList.First();
37     while (pStmt)
38     {
39 	delete (*pStmt);
40 	pStmt = _stmtList.Next();
41     }
42     CegoProcCursor **pCur = _cursorList.First();
43     while ( pCur )
44     {
45 	delete (*pCur);
46 	pCur = _cursorList.Next();
47     }
48     CegoProcException **pExcep = _exceptionList.First();
49     while ( pExcep )
50     {
51 	delete *pExcep;
52 	pExcep = _exceptionList.Next();
53     }
54 }
55 
setVarList(const ListT<CegoProcVar> & varList)56 void CegoProcBlock::setVarList(const ListT<CegoProcVar>& varList)
57 {
58     _varList = varList;
59 }
60 
getVarList()61 ListT<CegoProcVar>& CegoProcBlock::getVarList()
62 {
63     return _varList;
64 }
65 
addCursor(const Chain & cursorName,CegoSelect * pSelect)66 void CegoProcBlock::addCursor(const Chain& cursorName, CegoSelect *pSelect)
67 {
68     CegoProcCursor **pCur = _cursorList.First();
69     while ( pCur )
70     {
71 	if ( (*pCur)->getName() == cursorName )
72 	{
73 	    Chain msg = Chain("Cursor ") + cursorName + Chain(" already defined");
74 	    throw Exception(EXLOC, msg);
75 	}
76 	pCur = _cursorList.Next();
77     }
78 
79     _cursorList.Insert(new CegoProcCursor(cursorName, pSelect));
80     return;
81 }
82 
getCursor(const Chain & cursorName)83 CegoProcCursor* CegoProcBlock::getCursor(const Chain &cursorName)
84 {
85     CegoProcCursor **pCur = _cursorList.First();
86     while ( pCur )
87     {
88 	if ( (*pCur)->getName() == cursorName )
89 	{
90 	    return *pCur;
91 	}
92 	pCur = _cursorList.Next();
93     }
94 
95     if ( _pParentBlock )
96     {
97 	return _pParentBlock->getCursor(cursorName);
98     }
99     else
100     {
101 	Chain msg = Chain("Unknown cursor ") + cursorName;
102 	throw Exception(EXLOC, msg);
103     }
104 }
105 
setParentBlock(CegoProcBlock * pParentBlock)106 void CegoProcBlock::setParentBlock(CegoProcBlock* pParentBlock)
107 {
108     _pParentBlock = pParentBlock;
109 }
110 
getParentBlock()111 CegoProcBlock* CegoProcBlock::getParentBlock()
112 {
113     return _pParentBlock;
114 }
115 
setValue(const Chain & varName,const CegoFieldValue & fv)116 void CegoProcBlock::setValue(const Chain& varName, const CegoFieldValue& fv)
117 {
118     CegoProcVar *pVar = _varList.Find(CegoProcVar(varName));
119     if ( pVar )
120     {
121 	pVar->setValue(fv);
122     }
123     else
124     {
125 	if ( _pParentBlock )
126 	{
127 	    _pParentBlock->setValue(varName, fv);
128 	}
129 	else
130 	{
131 	    Chain msg = Chain("Unknown variable ") + varName;
132 	    throw Exception(EXLOC, msg);
133 	}
134     }
135 }
136 
getValue(const Chain & varName)137 CegoFieldValue CegoProcBlock::getValue(const Chain& varName)
138 {
139     if ( varName ==  Chain(EXCEPINFO))
140 	return CegoFieldValue(VARCHAR_TYPE, _exceptionMsg);
141 
142     CegoProcVar *pVar = _varList.Find(CegoProcVar(varName));
143     CegoFieldValue fv;
144     if ( pVar )
145     {
146 	return pVar->getValue();
147     }
148     else
149     {
150 	if ( _pParentBlock )
151 	{
152 	    return _pParentBlock->getValue(varName);
153 	}
154 	else
155 	{
156 	    Chain msg = Chain("Unknown variable ") + varName;
157 	    throw Exception(EXLOC, msg);
158 	}
159     }
160 }
161 
addStatement(CegoProcStmt * pS)162 void CegoProcBlock::addStatement(CegoProcStmt* pS)
163 {
164     _stmtList.Insert(pS);
165 }
166 
addException(CegoProcException * pE)167 void CegoProcBlock::addException(CegoProcException* pE)
168 {
169     _exceptionList.Insert(pE);
170 }
171 
execute(ListT<CegoField> * pFVL)172 CegoException CegoProcBlock::execute(ListT<CegoField> *pFVL)
173 {
174     CegoProcStmt **pStmt = _stmtList.First();
175 
176     while (pStmt)
177     {
178 	try
179 	{
180 	    CegoException excep;
181 
182 	    if ( ( excep = (*pStmt)->execute() ) != NONE_EXCEP )
183 	    {
184 		if ( excep == RETURN_EXCEP )
185 		{
186 		    closeBlock();
187 		    return excep;
188 		}
189 		CegoProcException **pException = _exceptionList.First();
190 		while ( pException )
191 		{
192 		    if ( (*pException)->getException() == excep || (*pException)->getException() == ANY_EXCEP )
193 		    {
194 			CegoProcBlock *pBlock = (*pException)->getBlock();
195 			pBlock->setExceptionMsg( getExceptionMsg() );
196 			if ( pBlock->execute() == RETURN_EXCEP )
197 			    return RETURN_EXCEP;
198 			excep = NONE_EXCEP;
199 		    }
200 		    pException = _exceptionList.Next();
201 		}
202 		// propagate exception to parent block
203 		if ( excep != NONE_EXCEP &&  _pParentBlock )
204 		    _pParentBlock->setExceptionMsg( getExceptionMsg() );
205 		closeBlock();
206 		return excep;
207 	    }
208 	}
209 	catch ( Exception e )
210 	{
211 	    Chain errMsg;
212 	    e.pop(errMsg);
213 	    Chain plainStmt;
214 	    (*pStmt)->toChain().replaceAll(Chain("\n"), Chain(" "), plainStmt);
215 	    Chain msg = Chain("Procedure block error at stmt <") + plainStmt + Chain("> : ") + errMsg;
216 	    closeBlock();
217 
218 	    throw Exception(EXLOC, msg);
219 
220 	}
221 	pStmt = _stmtList.Next();
222     }
223 
224     closeBlock();
225 
226     return NONE_EXCEP;
227 }
228 
cleanBlock()229 void CegoProcBlock::cleanBlock()
230 {
231     CegoProcCursor **pCur = _cursorList.First();
232     while ( pCur )
233     {
234 	(*pCur)->reset();
235 	pCur = _cursorList.Next();
236     }
237 }
238 
closeBlock()239 void CegoProcBlock::closeBlock()
240 {
241     CegoProcCursor **pCur = _cursorList.First();
242     while ( pCur )
243     {
244 	(*pCur)->close();
245 	pCur = _cursorList.Next();
246     }
247 }
248 
setRetVal(const CegoFieldValue & retVal)249 void CegoProcBlock::setRetVal(const CegoFieldValue& retVal)
250 {
251     if ( _pParentBlock )
252 	_pParentBlock->setRetVal(retVal);
253     else
254 	_retVal = retVal;
255 }
256 
getRetVal()257 CegoFieldValue& CegoProcBlock::getRetVal()
258 {
259     return _retVal;
260 }
261 
setExceptionMsg(const Chain msg)262 void CegoProcBlock::setExceptionMsg(const Chain msg)
263 {
264     _exceptionMsg = msg;
265 }
266 
getExceptionMsg() const267 Chain CegoProcBlock::getExceptionMsg() const
268 {
269     return _exceptionMsg;
270 }
271 
getStmtList()272 ListT<CegoProcStmt*>& CegoProcBlock::getStmtList()
273 {
274     return _stmtList;
275 }
276 
getExceptionList() const277 const ListT<CegoProcException*>& CegoProcBlock::getExceptionList() const
278 {
279     return _exceptionList;
280 }
281 
toChain(const Chain & indent) const282 Chain CegoProcBlock::toChain(const Chain& indent) const
283 {
284     Chain s;
285     CegoProcVar *pVar = _varList.First();
286     while ( pVar )
287     {
288 	if ( pVar->getVarType() == CegoProcVar::BLOCKVAR )
289 	{
290 	    s += indent + Chain("var ");
291 	    s += pVar->getName();
292 	    switch ( pVar->getType() )
293 	    {
294 	    case INT_TYPE:
295 		s += Chain(" int;\n");
296 		break;
297 	    case LONG_TYPE:
298 		s += Chain(" long;\n");
299 		break;
300 	    case VARCHAR_TYPE:
301 		s += Chain(" string(") + Chain(pVar->getLength()) + Chain(");\n");
302 		break;
303 	    case BIGINT_TYPE:
304 		s += Chain(" bigint(") + Chain(pVar->getLength()) + Chain(");\n");
305 		break;
306 	    case DECIMAL_TYPE:
307 		s += Chain(" decimal(") + Chain(pVar->getLength()) + Chain(");\n");
308 		break;
309 	    case FIXED_TYPE:
310 		s += Chain(" fixed(") + Chain(pVar->getLength()) + Chain(");\n");
311 		break;
312 	    case BOOL_TYPE:
313 		s += Chain(" bool;\n");
314 		break;
315 	    case DATETIME_TYPE:
316 		s += Chain(" datetime;\n");
317 		break;
318 	    case FLOAT_TYPE:
319 		s += Chain(" float;\n");
320 		break;
321 	    case DOUBLE_TYPE:
322 		s += Chain(" double;\n");
323 		break;
324 	    case SMALLINT_TYPE:
325 		s += Chain(" smallint;\n");
326 		break;
327 	    case TINYINT_TYPE:
328 		s += Chain(" tinyint;\n");
329 		break;
330 	    case NULL_TYPE:
331 		s += Chain(" null;\n");
332 		break;
333 	    case BLOB_TYPE:
334 		s += Chain(" blob;\n");
335 		break;
336 	    case CLOB_TYPE:
337 		s += Chain(" clob;\n");
338 		break;
339 	    case PAGEID_TYPE:
340 		break;
341 	    }
342 	}
343 
344 	pVar = _varList.Next();
345     }
346 
347     CegoProcStmt **pStmt = _stmtList.First();
348     while (pStmt)
349     {
350 	s += (*pStmt)->toChain(indent) + Chain(";\n");
351 	pStmt = _stmtList.Next();
352     }
353 
354     CegoProcException **pException = _exceptionList.First();
355     while ( pException )
356     {
357 	s += Chain("exception when ") + (*pException)->toChain() + Chain("\nthen\n");
358 	s += (*pException)->getBlock()->toChain(indent + Chain(DEFAULTINDENT));
359 	pException = _exceptionList.Next();
360     }
361 
362     return s;
363 }
364 
dbFormat(CegoDatabaseFormater * pForm) const365 Chain CegoProcBlock::dbFormat(CegoDatabaseFormater *pForm) const
366 {
367     return pForm->formatProcBlock(_varList, _stmtList, _exceptionList);
368 }
369 
setTriggerValueList(ListT<CegoField> * pTriggerValueList)370 void CegoProcBlock::setTriggerValueList(ListT<CegoField>* pTriggerValueList)
371 {
372     _pTriggerValueList = pTriggerValueList;
373 }
374 
getTriggerValueList()375 ListT<CegoField>* CegoProcBlock::getTriggerValueList()
376 {
377     return _pTriggerValueList;
378 }
379