MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DbtupStoredProcDef.cpp
1 /*
2  Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 
19 #define DBTUP_C
20 #define DBTUP_STORE_PROC_DEF_CPP
21 #include "Dbtup.hpp"
22 #include <RefConvert.hpp>
23 #include <ndb_limits.h>
24 #include <pc.hpp>
25 
26 /* ---------------------------------------------------------------- */
27 /* ---------------------------------------------------------------- */
28 /* ------------ADD/DROP STORED PROCEDURE MODULE ------------------- */
29 /* ---------------------------------------------------------------- */
30 /* ---------------------------------------------------------------- */
31 void Dbtup::execSTORED_PROCREQ(Signal* signal)
32 {
33  OperationrecPtr regOperPtr;
34  TablerecPtr regTabPtr;
35  jamEntry();
36  regOperPtr.i = signal->theData[0];
37  c_operation_pool.getPtr(regOperPtr);
38  regTabPtr.i = signal->theData[1];
39  ptrCheckGuard(regTabPtr, cnoOfTablerec, tablerec);
40 
41  Uint32 requestInfo = signal->theData[3];
42  TransState trans_state= get_trans_state(regOperPtr.p);
43  ndbrequire(trans_state == TRANS_IDLE ||
44  ((trans_state == TRANS_ERROR_WAIT_STORED_PROCREQ) &&
45  (requestInfo == ZSTORED_PROCEDURE_DELETE)));
46  ndbrequire(regTabPtr.p->tableStatus == DEFINED);
47  /*
48  * Also store count of procs called from non-API scans.
49  * It can be done here since seize/release always succeeds.
50  * The count is only used under -DERROR_INSERT via DUMP.
51  */
52  BlockReference apiBlockref = signal->theData[5];
53  switch (requestInfo) {
54  case ZSCAN_PROCEDURE:
55  {
56  jam();
57 #if defined VM_TRACE || defined ERROR_INSERT
58  storedProcCountNonAPI(apiBlockref, +1);
59 #endif
60  SectionHandle handle(this, signal);
61  ndbrequire(handle.m_cnt == 1);
62 
63  scanProcedure(signal,
64  regOperPtr.p,
65  &handle,
66  false); // Not copy
67  break;
68  }
69  case ZCOPY_PROCEDURE:
70  jam();
71 #if defined VM_TRACE || defined ERROR_INSERT
72  storedProcCountNonAPI(apiBlockref, +1);
73 #endif
74  copyProcedure(signal, regTabPtr, regOperPtr.p);
75  break;
76  case ZSTORED_PROCEDURE_DELETE:
77  jam();
78 #if defined VM_TRACE || defined ERROR_INSERT
79  storedProcCountNonAPI(apiBlockref, -1);
80 #endif
81  deleteScanProcedure(signal, regOperPtr.p);
82  break;
83  default:
84  ndbrequire(false);
85  }//switch
86 }//Dbtup::execSTORED_PROCREQ()
87 
88 void Dbtup::storedProcCountNonAPI(BlockReference apiBlockref, int add_del)
89 {
90  BlockNumber apiBlockno = refToBlock(apiBlockref);
91  if (apiBlockno < MIN_API_BLOCK_NO) {
92  ndbassert(blockToMain(apiBlockno) == BACKUP ||
93  blockToMain(apiBlockno) == SUMA ||
94  blockToMain(apiBlockno) == DBLQH ||
95  blockToMain(apiBlockno) == DBSPJ);
96  if (add_del == +1) {
97  jam();
98  c_storedProcCountNonAPI++;
99  } else if (add_del == -1) {
100  jam();
101  ndbassert(c_storedProcCountNonAPI > 0);
102  c_storedProcCountNonAPI--;
103  } else {
104  ndbassert(false);
105  }
106  }
107 }
108 
109 void Dbtup::deleteScanProcedure(Signal* signal,
110  Operationrec* regOperPtr)
111 {
112  StoredProcPtr storedPtr;
113  Uint32 storedProcId = signal->theData[4];
114  c_storedProcPool.getPtr(storedPtr, storedProcId);
115  ndbrequire(storedPtr.p->storedCode != ZSTORED_PROCEDURE_FREE);
116  if (unlikely(storedPtr.p->storedCode == ZCOPY_PROCEDURE))
117  {
118  releaseCopyProcedure();
119  }
120  else
121  {
122  /* ZSCAN_PROCEDURE */
123  releaseSection(storedPtr.p->storedProcIVal);
124  }
125  storedPtr.p->storedCode = ZSTORED_PROCEDURE_FREE;
126  storedPtr.p->storedProcIVal= RNIL;
127  c_storedProcPool.release(storedPtr);
128 
129  set_trans_state(regOperPtr, TRANS_IDLE);
130  signal->theData[0] = regOperPtr->userpointer;
131  signal->theData[1] = storedProcId;
132  BlockReference lqhRef = calcInstanceBlockRef(DBLQH);
133  sendSignal(lqhRef, GSN_STORED_PROCCONF, signal, 2, JBB);
134 }//Dbtup::deleteScanProcedure()
135 
136 void Dbtup::scanProcedure(Signal* signal,
137  Operationrec* regOperPtr,
138  SectionHandle* handle,
139  bool isCopy)
140 {
141  /* Size a stored procedure record, and link the
142  * stored procedure AttrInfo section from it
143  */
144  ndbrequire( handle->m_cnt == 1 );
145  ndbrequire( handle->m_ptr[0].p->m_sz > 0 );
146 
147  StoredProcPtr storedPtr;
148  c_storedProcPool.seize(storedPtr);
149  ndbrequire(storedPtr.i != RNIL);
150  storedPtr.p->storedCode = (isCopy)? ZCOPY_PROCEDURE : ZSCAN_PROCEDURE;
151  Uint32 lenAttrInfo= handle->m_ptr[0].p->m_sz;
152  storedPtr.p->storedProcIVal= handle->m_ptr[0].i;
153  handle->clear();
154 
155  set_trans_state(regOperPtr, TRANS_IDLE);
156 
157  if (lenAttrInfo >= ZATTR_BUFFER_SIZE) { // yes ">="
158  jam();
159  // send REF and change state
160  storedProcBufferSeizeErrorLab(signal,
161  regOperPtr,
162  storedPtr.i,
163  ZSTORED_TOO_MUCH_ATTRINFO_ERROR);
164  return;
165  }
166 
167  signal->theData[0] = regOperPtr->userpointer;
168  signal->theData[1] = storedPtr.i;
169 
170  BlockReference lqhRef = calcInstanceBlockRef(DBLQH);
171  sendSignal(lqhRef, GSN_STORED_PROCCONF, signal, 2, JBB);
172 }//Dbtup::scanProcedure()
173 
174 void Dbtup::allocCopyProcedure()
175 {
176  /* We allocate some segments and initialise them with
177  * Attribute Ids for the 'worst case' table.
178  * At run time we can use prefixes of this data.
179  *
180  * TODO : Consider using read packed 'read all columns' word once
181  * updatePacked supported.
182  */
183  Uint32 iVal= RNIL;
184  Uint32 ahWord;
185 
186  for (Uint32 attrNum=0; attrNum < MAX_ATTRIBUTES_IN_TABLE; attrNum++)
187  {
188  AttributeHeader::init(&ahWord, attrNum, 0);
189  ndbrequire(appendToSection(iVal, &ahWord, 1));
190  }
191 
192  /* Add space for extra attrs */
193  ahWord = 0;
194  for (Uint32 extra=0; extra < EXTRA_COPY_PROC_WORDS; extra++)
195  ndbrequire(appendToSection(iVal, &ahWord, 1));
196 
197  cCopyProcedure= iVal;
198  cCopyLastSeg= RNIL;
199  cCopyOverwrite= 0;
200  cCopyOverwriteLen= 0;
201 }
202 
203 void Dbtup::freeCopyProcedure()
204 {
205  /* Should only be called when shutting down node.
206  */
207  releaseSection(cCopyProcedure);
208  cCopyProcedure=RNIL;
209 }
210 
211 void Dbtup::prepareCopyProcedure(Uint32 numAttrs,
212  Uint16 tableBits)
213 {
214  /* Set length of copy procedure section to the
215  * number of attributes supplied
216  */
217  ndbassert(numAttrs <= MAX_ATTRIBUTES_IN_TABLE);
218  ndbassert(cCopyProcedure != RNIL);
219  ndbassert(cCopyLastSeg == RNIL);
220  ndbassert(cCopyOverwrite == 0);
221  ndbassert(cCopyOverwriteLen == 0);
222  Ptr<SectionSegment> first;
223  g_sectionSegmentPool.getPtr(first, cCopyProcedure);
224 
225  /* Record original 'last segment' of section */
226  cCopyLastSeg= first.p->m_lastSegment;
227 
228  /* Check table bits to see if we need to do extra reads */
229  Uint32 extraAttrIds[EXTRA_COPY_PROC_WORDS];
230  Uint32 extraReads = 0;
231 
232  if (tableBits & Tablerec::TR_ExtraRowGCIBits)
233  {
234  AttributeHeader ah(AttributeHeader::ROW_GCI64,0);
235  extraAttrIds[extraReads++] = ah.m_value;
236  }
237  if (tableBits & Tablerec::TR_ExtraRowAuthorBits)
238  {
239  AttributeHeader ah(AttributeHeader::ROW_AUTHOR,0);
240  extraAttrIds[extraReads++] = ah.m_value;
241  }
242 
243  /* Modify section to represent relevant prefix
244  * of code by modifying size and lastSegment
245  */
246  Uint32 newSize = numAttrs + extraReads;
247  first.p->m_sz= newSize;
248 
249  if (extraReads)
250  {
251  cCopyOverwrite= numAttrs;
252  cCopyOverwriteLen = extraReads;
253 
254  ndbrequire(writeToSection(first.i, numAttrs, extraAttrIds, extraReads));
255  }
256 
257  /* Trim section size and lastSegment */
258  Ptr<SectionSegment> curr= first;
259  while(newSize > SectionSegment::DataLength)
260  {
261  g_sectionSegmentPool.getPtr(curr, curr.p->m_nextSegment);
262  newSize-= SectionSegment::DataLength;
263  }
264  first.p->m_lastSegment= curr.i;
265 }
266 
267 void Dbtup::releaseCopyProcedure()
268 {
269  /* Return Copy Procedure section to original length */
270  ndbassert(cCopyProcedure != RNIL);
271  ndbassert(cCopyLastSeg != RNIL);
272 
273  Ptr<SectionSegment> first;
274  g_sectionSegmentPool.getPtr(first, cCopyProcedure);
275 
276  ndbassert(first.p->m_sz <= MAX_COPY_PROC_LEN);
277  first.p->m_sz= MAX_COPY_PROC_LEN;
278  first.p->m_lastSegment= cCopyLastSeg;
279 
280  if (cCopyOverwriteLen)
281  {
282  ndbassert(cCopyOverwriteLen <= EXTRA_COPY_PROC_WORDS);
283  Uint32 attrids[EXTRA_COPY_PROC_WORDS];
284  for (Uint32 i=0; i < cCopyOverwriteLen; i++)
285  {
286  AttributeHeader ah(cCopyOverwrite + i, 0);
287  attrids[i] = ah.m_value;
288  }
289  ndbrequire(writeToSection(first.i, cCopyOverwrite, attrids, cCopyOverwriteLen));
290  cCopyOverwriteLen= 0;
291  cCopyOverwrite= 0;
292  }
293 
294  cCopyLastSeg= RNIL;
295 }
296 
297 
298 void Dbtup::copyProcedure(Signal* signal,
299  TablerecPtr regTabPtr,
300  Operationrec* regOperPtr)
301 {
302  /* We create a stored procedure for the fragment copy scan
303  * This is done by trimming a 'read all columns in order'
304  * program to the correct length for this table and
305  * using that to create the procedure
306  * This assumes that there is only one fragment copy going
307  * on at any time, which is verified by checking
308  * cCopyLastSeg == RNIL before starting each copy
309  *
310  * If the table has extra per-row metainformation that
311  * needs copied then we add that to the copy procedure
312  * as well.
313  */
314  prepareCopyProcedure(regTabPtr.p->m_no_of_attributes,
315  regTabPtr.p->m_bits);
316 
317  SectionHandle handle(this);
318  handle.m_cnt=1;
319  handle.m_ptr[0].i= cCopyProcedure;
320  getSections(handle.m_cnt, handle.m_ptr);
321 
322  scanProcedure(signal,
323  regOperPtr,
324  &handle,
325  true); // isCopy
326 }//Dbtup::copyProcedure()
327 
328 void Dbtup::storedProcBufferSeizeErrorLab(Signal* signal,
329  Operationrec* regOperPtr,
330  Uint32 storedProcPtr,
331  Uint32 errorCode)
332 {
333  regOperPtr->m_any_value = 0;
334  set_trans_state(regOperPtr, TRANS_ERROR_WAIT_STORED_PROCREQ);
335  signal->theData[0] = regOperPtr->userpointer;
336  signal->theData[1] = errorCode;
337  signal->theData[2] = storedProcPtr;
338  BlockReference lqhRef = calcInstanceBlockRef(DBLQH);
339  sendSignal(lqhRef, GSN_STORED_PROCREF, signal, 3, JBB);
340 }//Dbtup::storedSeizeAttrinbufrecErrorLab()
341