1 /*
2 Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 #define DBTUP_C
27 #define DBTUP_TRIGGER_CPP
28 #include "Dbtup.hpp"
29 #include <RefConvert.hpp>
30 #include <ndb_limits.h>
31 #include <pc.hpp>
32 #include <AttributeDescriptor.hpp>
33 #include "AttributeOffset.hpp"
34 #include <AttributeHeader.hpp>
35 #include <signaldata/FireTrigOrd.hpp>
36 #include <signaldata/CreateTrig.hpp>
37 #include <signaldata/CreateTrigImpl.hpp>
38 #include <signaldata/DropTrig.hpp>
39 #include <signaldata/DropTrigImpl.hpp>
40 #include <signaldata/TuxMaint.hpp>
41 #include <signaldata/AlterIndxImpl.hpp>
42 #include <signaldata/ScanFrag.hpp>
43 #include "../dblqh/Dblqh.hpp"
44
45 #define JAM_FILE_ID 423
46
47
48 /* **************************************************************** */
49 /* ---------------------------------------------------------------- */
50 /* ----------------------- TRIGGER HANDLING ----------------------- */
51 /* ---------------------------------------------------------------- */
52 /* **************************************************************** */
53
54 DLList<Dbtup::TupTriggerData>*
findTriggerList(Tablerec * table,TriggerType::Value ttype,TriggerActionTime::Value ttime,TriggerEvent::Value tevent)55 Dbtup::findTriggerList(Tablerec* table,
56 TriggerType::Value ttype,
57 TriggerActionTime::Value ttime,
58 TriggerEvent::Value tevent)
59 {
60 DLList<TupTriggerData>* tlist = NULL;
61 switch (ttype) {
62 case TriggerType::SUBSCRIPTION:
63 case TriggerType::SUBSCRIPTION_BEFORE:
64 switch (tevent) {
65 case TriggerEvent::TE_INSERT:
66 jam();
67 if (ttime == TriggerActionTime::TA_DETACHED)
68 tlist = &table->subscriptionInsertTriggers;
69 break;
70 case TriggerEvent::TE_UPDATE:
71 jam();
72 if (ttime == TriggerActionTime::TA_DETACHED)
73 tlist = &table->subscriptionUpdateTriggers;
74 break;
75 case TriggerEvent::TE_DELETE:
76 jam();
77 if (ttime == TriggerActionTime::TA_DETACHED)
78 tlist = &table->subscriptionDeleteTriggers;
79 break;
80 default:
81 break;
82 }
83 break;
84 case TriggerType::SECONDARY_INDEX:
85 case TriggerType::REORG_TRIGGER:
86 switch (tevent) {
87 case TriggerEvent::TE_INSERT:
88 jam();
89 if (ttime == TriggerActionTime::TA_AFTER)
90 tlist = &table->afterInsertTriggers;
91 break;
92 case TriggerEvent::TE_UPDATE:
93 jam();
94 if (ttime == TriggerActionTime::TA_AFTER)
95 tlist = &table->afterUpdateTriggers;
96 break;
97 case TriggerEvent::TE_DELETE:
98 jam();
99 if (ttime == TriggerActionTime::TA_AFTER)
100 tlist = &table->afterDeleteTriggers;
101 break;
102 default:
103 break;
104 }
105 break;
106 case TriggerType::ORDERED_INDEX:
107 switch (tevent) {
108 case TriggerEvent::TE_CUSTOM:
109 jam();
110 if (ttime == TriggerActionTime::TA_CUSTOM)
111 tlist = &table->tuxCustomTriggers;
112 break;
113 default:
114 break;
115 }
116 break;
117 case TriggerType::READ_ONLY_CONSTRAINT:
118 switch (tevent) {
119 case TriggerEvent::TE_UPDATE:
120 jam();
121 if (ttime == TriggerActionTime::TA_AFTER)
122 tlist = &table->constraintUpdateTriggers;
123 break;
124 default:
125 break;
126 }
127 break;
128 case TriggerType::FK_PARENT:
129 case TriggerType::FK_CHILD:
130 switch (tevent) {
131 case TriggerEvent::TE_INSERT:
132 jam();
133 if (ttime == TriggerActionTime::TA_DEFERRED)
134 tlist = &table->deferredInsertTriggers;
135 else if (ttime == TriggerActionTime::TA_AFTER)
136 tlist = &table->afterInsertTriggers;
137 break;
138 case TriggerEvent::TE_UPDATE:
139 jam();
140 if (ttime == TriggerActionTime::TA_DEFERRED)
141 tlist = &table->deferredUpdateTriggers;
142 else if (ttime == TriggerActionTime::TA_AFTER)
143 tlist = &table->afterUpdateTriggers;
144 break;
145 case TriggerEvent::TE_DELETE:
146 jam();
147 if (ttime == TriggerActionTime::TA_DEFERRED)
148 tlist = &table->deferredDeleteTriggers;
149 else if (ttime == TriggerActionTime::TA_AFTER)
150 tlist = &table->afterDeleteTriggers;
151 break;
152 default:
153 break;
154 }
155 break;
156 default:
157 break;
158 }
159 return tlist;
160 }
161
162 // Trigger signals
163 void
execCREATE_TRIG_IMPL_REQ(Signal * signal)164 Dbtup::execCREATE_TRIG_IMPL_REQ(Signal* signal)
165 {
166 jamEntry();
167 if (!assembleFragments(signal))
168 {
169 jam();
170 return;
171 }
172
173 const CreateTrigImplReq* req = (const CreateTrigImplReq*)signal->getDataPtr();
174 const Uint32 senderRef = req->senderRef;
175 const Uint32 senderData = req->senderData;
176 const Uint32 tableId = req->tableId;
177 const Uint32 triggerId = req->triggerId;
178 const Uint32 triggerInfo = req->triggerInfo;
179
180 CreateTrigRef::ErrorCode error = CreateTrigRef::NoError;
181
182 AttributeMask mask;
183 SectionHandle handle(this, signal);
184 if (handle.m_cnt <= CreateTrigImplReq::ATTRIBUTE_MASK_SECTION)
185 {
186 jam();
187 ndbassert(false);
188 error = CreateTrigRef::BadRequestType;
189 }
190 else
191 {
192 SegmentedSectionPtr ptr;
193 handle.getSection(ptr, CreateTrigImplReq::ATTRIBUTE_MASK_SECTION);
194 ndbrequire(ptr.sz == mask.getSizeInWords());
195 ::copy(mask.rep.data, ptr);
196 }
197
198 releaseSections(handle);
199
200 if (error != CreateTrigRef::NoError)
201 {
202 goto err;
203 }
204
205 {
206 // Find table
207 TablerecPtr tabPtr;
208 tabPtr.i = req->tableId;
209 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
210
211 if (tabPtr.p->tableStatus != DEFINED )
212 {
213 jam();
214 error = CreateTrigRef::InvalidTable;
215 }
216 // Create trigger and associate it with the table
217 else if (createTrigger(tabPtr.p, req, mask))
218 {
219 jam();
220 // Send conf
221 CreateTrigImplConf* conf = (CreateTrigImplConf*)signal->getDataPtrSend();
222 conf->senderRef = reference();
223 conf->senderData = senderData;
224 conf->tableId = tableId;
225 conf->triggerId = triggerId;
226 conf->triggerInfo = triggerInfo;
227
228 sendSignal(senderRef, GSN_CREATE_TRIG_IMPL_CONF,
229 signal, CreateTrigImplConf::SignalLength, JBB);
230 return;
231 }
232 else
233 {
234 jam();
235 error = CreateTrigRef::TooManyTriggers;
236 }
237 }
238
239 err:
240 ndbassert(error != CreateTrigRef::NoError);
241 // Send ref
242 CreateTrigImplRef* ref = (CreateTrigImplRef*)signal->getDataPtrSend();
243 ref->senderRef = reference();
244 ref->senderData = senderData;
245 ref->tableId = tableId;
246 ref->triggerId = triggerId;
247 ref->triggerInfo = triggerInfo;
248 ref->errorCode = error;
249
250 sendSignal(senderRef, GSN_CREATE_TRIG_IMPL_REF,
251 signal, CreateTrigImplRef::SignalLength, JBB);
252 }
253
254 void
execDROP_TRIG_IMPL_REQ(Signal * signal)255 Dbtup::execDROP_TRIG_IMPL_REQ(Signal* signal)
256 {
257 jamEntry();
258 const DropTrigImplReq* req = (const DropTrigImplReq*)signal->getDataPtr();
259 const Uint32 senderRef = req->senderRef;
260 const Uint32 senderData = req->senderData;
261 const Uint32 tableId = req->tableId;
262 const Uint32 indexId = req->indexId;
263 const Uint32 triggerId = req->triggerId;
264 const Uint32 triggerInfo = req->triggerInfo;
265 const Uint32 receiverRef = req->receiverRef;
266
267 // Find table
268 TablerecPtr tabPtr;
269 tabPtr.i = req->tableId;
270 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
271
272 // Drop trigger
273 Uint32 r = dropTrigger(tabPtr.p, req, refToBlock(receiverRef));
274 if (r == 0)
275 {
276 /**
277 * make sure that any trigger data is sent before DROP_TRIG_CONF
278 * NOTE: This is only needed for SUMA triggers
279 * (which are the only buffered ones) but it shouldn't
280 * be too bad to do it for all triggers...
281 */
282 flush_ndbmtd_suma_buffer(signal);
283
284 // Send conf
285 DropTrigImplConf* conf = (DropTrigImplConf*)signal->getDataPtrSend();
286 conf->senderRef = reference();
287 conf->senderData = senderData;
288 conf->tableId = tableId;
289 conf->triggerId = triggerId;
290
291 sendSignal(senderRef, GSN_DROP_TRIG_IMPL_CONF,
292 signal, DropTrigImplConf::SignalLength, JBB);
293
294 // Set ordered index to Dropping in same timeslice
295 TriggerType::Value ttype = TriggerInfo::getTriggerType(triggerInfo);
296 if (ttype == TriggerType::ORDERED_INDEX)
297 {
298 jam();
299 AlterIndxImplReq* areq = (AlterIndxImplReq*)signal->getDataPtrSend();
300 areq->senderRef = 0; // no CONF
301 areq->senderData = 0;
302 areq->requestType = AlterIndxImplReq::AlterIndexOffline;
303 areq->tableId = tableId;
304 areq->tableVersion = 0;
305 areq->indexId = indexId; // index id
306 areq->indexVersion = 0;
307 areq->indexType = DictTabInfo::OrderedIndex;
308 EXECUTE_DIRECT(DBTUX, GSN_ALTER_INDX_IMPL_REQ,
309 signal, AlterIndxImplReq::SignalLength);
310 }
311 } else {
312 // Send ref
313 DropTrigImplRef* ref = (DropTrigImplRef*)signal->getDataPtrSend();
314 ref->senderRef = reference();
315 ref->senderData = senderData;
316 ref->tableId = tableId;
317 ref->triggerId = triggerId;
318 ref->errorCode = r;
319 sendSignal(senderRef, GSN_DROP_TRIG_IMPL_REF,
320 signal, DropTrigImplRef::SignalLength, JBB);
321 }
322 }
323
324 /* ---------------------------------------------------------------- */
325 /* ------------------------- createTrigger ------------------------ */
326 /* */
327 /* Creates a new trigger record by fetching one from the trigger */
328 /* pool and associates it with the given table. */
329 /* Trigger type can be one of secondary_index, subscription, */
330 /* constraint(NYI), foreign_key(NYI), schema_upgrade(NYI), */
331 /* api_trigger(NYI) or sql_trigger(NYI). */
332 /* Note that this method only checks for total number of allowed */
333 /* triggers. Checking the number of allowed triggers per table is */
334 /* done by TRIX. */
335 /* */
336 /* ---------------------------------------------------------------- */
337 bool
createTrigger(Tablerec * table,const CreateTrigImplReq * req,const AttributeMask & mask)338 Dbtup::createTrigger(Tablerec* table,
339 const CreateTrigImplReq* req,
340 const AttributeMask& mask)
341 {
342 if (ERROR_INSERTED(4003)) {
343 CLEAR_ERROR_INSERT_VALUE;
344 return false;
345 }
346
347 const Uint32 tinfo = req->triggerInfo;
348 TriggerType::Value ttype = TriggerInfo::getTriggerType(tinfo);
349 TriggerActionTime::Value ttime = TriggerInfo::getTriggerActionTime(tinfo);
350 TriggerEvent::Value tevent = TriggerInfo::getTriggerEvent(tinfo);
351
352 int cnt;
353 struct {
354 TriggerEvent::Value event;
355 DLList<TupTriggerData> * list;
356 TriggerPtr ptr;
357 } tmp[3];
358
359 if (ttype == TriggerType::SECONDARY_INDEX ||
360 ttype == TriggerType::REORG_TRIGGER)
361 {
362 jam();
363 cnt = 3;
364 tmp[0].event = TriggerEvent::TE_INSERT;
365 tmp[1].event = TriggerEvent::TE_UPDATE;
366 tmp[2].event = TriggerEvent::TE_DELETE;
367 }
368 else if (ttype == TriggerType::FK_PARENT)
369 {
370 jam();
371 cnt = 2;
372 tmp[0].event = TriggerEvent::TE_UPDATE;
373 tmp[1].event = TriggerEvent::TE_DELETE;
374 }
375 else if (ttype == TriggerType::FK_CHILD)
376 {
377 jam();
378 cnt = 2;
379 tmp[0].event = TriggerEvent::TE_INSERT;
380 tmp[1].event = TriggerEvent::TE_UPDATE;
381 }
382 else
383 {
384 jam();
385 cnt = 1;
386 tmp[0].event = tevent;
387 }
388
389 int i = 0;
390 for (i = 0; i<cnt; i++)
391 {
392 tmp[i].list = findTriggerList(table, ttype, ttime, tmp[i].event);
393 ndbrequire(tmp[i].list != NULL);
394
395 TriggerPtr tptr;
396 if (!tmp[i].list->seizeFirst(tptr))
397 {
398 jam();
399 goto err;
400 }
401
402 tmp[i].ptr = tptr;
403
404 // Set trigger id
405 tptr.p->triggerId = req->triggerId;
406 tptr.p->oldTriggerIds[0] = req->upgradeExtra[0];
407 tptr.p->oldTriggerIds[1] = req->upgradeExtra[1];
408 tptr.p->oldTriggerIds[2] = req->upgradeExtra[2];
409
410 // Set index id
411 tptr.p->indexId = req->indexId;
412
413 // Set trigger type etc
414 tptr.p->triggerType = ttype;
415 tptr.p->triggerActionTime = ttime;
416 tptr.p->triggerEvent = tevent;
417
418 tptr.p->sendBeforeValues = true;
419 if ((tptr.p->triggerType == TriggerType::SUBSCRIPTION) &&
420 ((tptr.p->triggerEvent == TriggerEvent::TE_UPDATE) ||
421 (tptr.p->triggerEvent == TriggerEvent::TE_DELETE))) {
422 jam();
423 tptr.p->sendBeforeValues = false;
424 }
425
426 if (ttype == TriggerType::REORG_TRIGGER)
427 {
428 jam();
429 tptr.p->sendBeforeValues = false;
430 }
431
432 /*
433 tptr.p->sendOnlyChangedAttributes = false;
434 if (((tptr.p->triggerType == TriggerType::SUBSCRIPTION) ||
435 (tptr.p->triggerType == TriggerType::SUBSCRIPTION_BEFORE)) &&
436 (tptr.p->triggerEvent == TriggerEvent::TE_UPDATE)) {
437 jam();
438 tptr.p->sendOnlyChangedAttributes = true;
439 }
440 */
441 tptr.p->sendOnlyChangedAttributes =
442 !TriggerInfo::getReportAllMonitoredAttributes(tinfo);
443
444 tptr.p->monitorAllAttributes = TriggerInfo::getMonitorAllAttributes(tinfo);
445 tptr.p->monitorReplicas = TriggerInfo::getMonitorReplicas(tinfo);
446 tptr.p->m_receiverRef = req->receiverRef;
447
448 if (tptr.p->monitorAllAttributes)
449 {
450 jam();
451 // Set all non-pk attributes
452 tptr.p->attributeMask.set();
453 for(Uint32 i = 0; i < table->m_no_of_attributes; i++) {
454 if (primaryKey(table, i))
455 tptr.p->attributeMask.clear(i);
456 }
457 }
458 else
459 {
460 jam();
461 // Set attribute mask
462 tptr.p->attributeMask = mask;
463 }
464 }
465 return true;
466
467 err:
468 for (--i; i >= 0; i--)
469 {
470 jam();
471 tmp[i].list->release(tmp[i].ptr);
472 }
473 return false;
474 }//Dbtup::createTrigger()
475
476 bool
primaryKey(Tablerec * const regTabPtr,Uint32 attrId)477 Dbtup::primaryKey(Tablerec* const regTabPtr, Uint32 attrId)
478 {
479 Uint32 attrDescriptorStart = regTabPtr->tabDescriptor;
480 Uint32 attrDescriptor = getTabDescrWord(attrDescriptorStart +
481 (attrId * ZAD_SIZE));
482 return (bool)AttributeDescriptor::getPrimaryKey(attrDescriptor);
483 }//Dbtup::primaryKey()
484
485 /* ---------------------------------------------------------------- */
486 /* -------------------------- dropTrigger ------------------------- */
487 /* */
488 /* Deletes a trigger record by disassociating it with the given */
489 /* table and returning it to the trigger pool. */
490 /* Trigger type can be one of secondary_index, subscription, */
491 /* constraint(NYI), foreign_key(NYI), schema_upgrade(NYI), */
492 /* api_trigger(NYI) or sql_trigger(NYI). */
493 /* */
494 /* ---------------------------------------------------------------- */
495 Uint32
dropTrigger(Tablerec * table,const DropTrigImplReq * req,BlockNumber receiver)496 Dbtup::dropTrigger(Tablerec* table, const DropTrigImplReq* req, BlockNumber receiver)
497 {
498 if (ERROR_INSERTED(4004)) {
499 CLEAR_ERROR_INSERT_VALUE;
500 return 9999;
501 }
502 Uint32 triggerId = req->triggerId;
503
504 const Uint32 tinfo = req->triggerInfo;
505 TriggerType::Value ttype = TriggerInfo::getTriggerType(tinfo);
506 TriggerActionTime::Value ttime = TriggerInfo::getTriggerActionTime(tinfo);
507 TriggerEvent::Value tevent = TriggerInfo::getTriggerEvent(tinfo);
508
509 // ndbout_c("Drop TupTrigger %u = %u %u %u %u by %u", triggerId, table, ttype, ttime, tevent, sender);
510
511 int cnt;
512 struct {
513 TriggerEvent::Value event;
514 DLList<TupTriggerData> * list;
515 TriggerPtr ptr;
516 } tmp[3];
517
518 if (ttype == TriggerType::SECONDARY_INDEX ||
519 ttype == TriggerType::REORG_TRIGGER)
520 {
521 jam();
522 cnt = 3;
523 tmp[0].event = TriggerEvent::TE_INSERT;
524 tmp[1].event = TriggerEvent::TE_UPDATE;
525 tmp[2].event = TriggerEvent::TE_DELETE;
526 }
527 else if (ttype == TriggerType::FK_PARENT)
528 {
529 jam();
530 cnt = 2;
531 tmp[0].event = TriggerEvent::TE_UPDATE;
532 tmp[1].event = TriggerEvent::TE_DELETE;
533 }
534 else if (ttype == TriggerType::FK_CHILD)
535 {
536 jam();
537 cnt = 2;
538 tmp[0].event = TriggerEvent::TE_INSERT;
539 tmp[1].event = TriggerEvent::TE_UPDATE;
540 }
541 else
542 {
543 jam();
544 cnt = 1;
545 tmp[0].event = tevent;
546 }
547
548 int i = 0;
549 for (i = 0; i<cnt; i++)
550 {
551 tmp[i].list = findTriggerList(table, ttype, ttime, tmp[i].event);
552 ndbrequire(tmp[i].list != NULL);
553
554 Ptr<TupTriggerData> ptr;
555 tmp[i].ptr.setNull();
556 for (tmp[i].list->first(ptr); !ptr.isNull(); tmp[i].list->next(ptr))
557 {
558 jam();
559 if (ptr.p->triggerId == triggerId)
560 {
561 if(ttype==TriggerType::SUBSCRIPTION &&
562 receiver != refToBlock(ptr.p->m_receiverRef))
563 {
564 /**
565 * You can only drop your own triggers for subscription triggers.
566 * Trigger IDs are private for each block.
567 *
568 * SUMA encodes information in the triggerId
569 *
570 * Backup doesn't really care about the Ids though.
571 */
572 jam();
573 continue;
574 }
575 jam();
576 tmp[i].ptr = ptr;
577 }
578 }
579 if (tmp[i].ptr.isNull())
580 {
581 jam();
582 return DropTrigRef::TriggerNotFound;
583 }
584 }
585
586 for (i = 0; i<cnt; i++)
587 {
588 jam();
589 tmp[i].list->release(tmp[i].ptr);
590 }
591 return 0;
592 }//Dbtup::dropTrigger()
593
594 void
execFIRE_TRIG_REQ(Signal * signal)595 Dbtup::execFIRE_TRIG_REQ(Signal* signal)
596 {
597 jam();
598 Uint32 opPtrI = signal->theData[0];
599 Uint32 pass = signal->theData[5];
600
601 FragrecordPtr regFragPtr;
602 OperationrecPtr regOperPtr;
603 TablerecPtr regTabPtr;
604 KeyReqStruct req_struct(this,
605 (When)(KRS_PRE_COMMIT_BASE +
606 (pass & TriggerPreCommitPass::TPCP_PASS_MAX)));
607
608 regOperPtr.i = opPtrI;
609
610 jamEntry();
611
612 c_operation_pool.getPtr(regOperPtr);
613
614 regFragPtr.i = regOperPtr.p->fragmentPtr;
615 Uint32 no_of_fragrec = cnoOfFragrec;
616 ptrCheckGuard(regFragPtr, no_of_fragrec, fragrecord);
617
618 TransState trans_state = get_trans_state(regOperPtr.p);
619 ndbrequire(trans_state == TRANS_STARTED);
620
621 Uint32 no_of_tablerec = cnoOfTablerec;
622 regTabPtr.i = regFragPtr.p->fragTableId;
623 ptrCheckGuard(regTabPtr, no_of_tablerec, tablerec);
624
625 req_struct.signal = signal;
626 req_struct.TC_ref = signal->theData[1];
627 req_struct.TC_index = signal->theData[2];
628 req_struct.trans_id1 = signal->theData[3];
629 req_struct.trans_id2 = signal->theData[4];
630 req_struct.m_reorg = regOperPtr.p->op_struct.bit_field.m_reorg;
631
632 PagePtr page;
633 Tuple_header* tuple_ptr = (Tuple_header*)
634 get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p);
635 req_struct.m_tuple_ptr = tuple_ptr;
636
637 OperationrecPtr lastOperPtr;
638 lastOperPtr.i = tuple_ptr->m_operation_ptr_i;
639 c_operation_pool.getPtr(lastOperPtr);
640 ndbassert(regOperPtr.p->op_struct.bit_field.m_reorg ==
641 lastOperPtr.p->op_struct.bit_field.m_reorg);
642
643 /**
644 * Deferred triggers should fire only once per primary key (per pass)
645 * regardless of no of DML on that primary key
646 *
647 * We keep track of this on *last* operation (which btw, implies that
648 * a trigger can't update "own" tuple...i.e first op would be better...)
649 *
650 */
651 if (!c_lqh->check_fire_trig_pass(lastOperPtr.p->userpointer, pass))
652 {
653 jam();
654 signal->theData[0] = 0;
655 signal->theData[1] = 0;
656 return;
657 }
658
659 /**
660 * This is deferred triggers...
661 * which is basically the same as detached,
662 * i.e before value is <before transaction>
663 * and after values is <after transaction>
664 * with the difference that they execute (fire) while
665 * still having a transaction context...
666 * i.e can abort transactions, modify transaction
667 */
668 req_struct.num_fired_triggers = 0;
669
670 /**
671 * See DbtupCommit re "Setting the op-list has this effect"
672 */
673 Uint32 save[2] = { lastOperPtr.p->nextActiveOp, lastOperPtr.p->prevActiveOp };
674 lastOperPtr.p->nextActiveOp = RNIL;
675 lastOperPtr.p->prevActiveOp = RNIL;
676
677 checkDeferredTriggers(&req_struct, lastOperPtr.p, regTabPtr.p, false);
678
679 lastOperPtr.p->nextActiveOp = save[0];
680 lastOperPtr.p->prevActiveOp = save[1];
681
682 signal->theData[0] = 0;
683 signal->theData[1] = req_struct.num_fired_triggers;
684 }
685
686 /* ---------------------------------------------------------------- */
687 /* -------------- checkImmediateTriggersAfterOp ------------------ */
688 /* */
689 /* Called after an insert, delete, or update operation takes */
690 /* place. Fetches before tuple for deletes and updates and */
691 /* after tuple for inserts and updates. */
692 /* Executes immediate triggers by sending FIRETRIGORD */
693 /* */
694 /* ---------------------------------------------------------------- */
695 void
checkImmediateTriggersAfterInsert(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)696 Dbtup::checkImmediateTriggersAfterInsert(KeyReqStruct *req_struct,
697 Operationrec *regOperPtr,
698 Tablerec *regTablePtr,
699 bool disk)
700 {
701 if (refToMain(req_struct->TC_ref) != DBTC) {
702 return;
703 }
704
705 if (regOperPtr->op_struct.bit_field.primary_replica)
706 {
707 if (! regTablePtr->afterInsertTriggers.isEmpty())
708 {
709 jam();
710 fireImmediateTriggers(req_struct,
711 regTablePtr->afterInsertTriggers,
712 regOperPtr,
713 disk);
714 }
715
716 if (! regTablePtr->deferredInsertTriggers.isEmpty())
717 {
718 checkDeferredTriggersDuringPrepare(req_struct,
719 regTablePtr->deferredInsertTriggers,
720 regOperPtr,
721 disk);
722 }
723 }
724 }
725
726 void
checkImmediateTriggersAfterUpdate(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)727 Dbtup::checkImmediateTriggersAfterUpdate(KeyReqStruct *req_struct,
728 Operationrec* regOperPtr,
729 Tablerec* regTablePtr,
730 bool disk)
731 {
732 if (refToMain(req_struct->TC_ref) != DBTC) {
733 return;
734 }
735
736 if (regOperPtr->op_struct.bit_field.primary_replica)
737 {
738 if (! regTablePtr->afterUpdateTriggers.isEmpty())
739 {
740 jam();
741 fireImmediateTriggers(req_struct,
742 regTablePtr->afterUpdateTriggers,
743 regOperPtr,
744 disk);
745 }
746
747 if (! regTablePtr->constraintUpdateTriggers.isEmpty())
748 {
749 jam();
750 fireImmediateTriggers(req_struct,
751 regTablePtr->constraintUpdateTriggers,
752 regOperPtr,
753 disk);
754 }
755
756 if (! regTablePtr->deferredUpdateTriggers.isEmpty())
757 {
758 jam();
759 checkDeferredTriggersDuringPrepare(req_struct,
760 regTablePtr->deferredUpdateTriggers,
761 regOperPtr,
762 disk);
763 }
764 }
765 }
766
767 void
checkImmediateTriggersAfterDelete(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)768 Dbtup::checkImmediateTriggersAfterDelete(KeyReqStruct *req_struct,
769 Operationrec* regOperPtr,
770 Tablerec* regTablePtr,
771 bool disk)
772 {
773 if (refToMain(req_struct->TC_ref) != DBTC) {
774 return;
775 }
776
777 if (regOperPtr->op_struct.bit_field.primary_replica)
778 {
779 if (! regTablePtr->afterDeleteTriggers.isEmpty())
780 {
781 fireImmediateTriggers(req_struct,
782 regTablePtr->afterDeleteTriggers,
783 regOperPtr,
784 disk);
785 }
786
787 if (! regTablePtr->deferredDeleteTriggers.isEmpty())
788 {
789 checkDeferredTriggersDuringPrepare(req_struct,
790 regTablePtr->deferredDeleteTriggers,
791 regOperPtr,
792 disk);
793 }
794 }
795 }
796
797 void
checkDeferredTriggersDuringPrepare(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)798 Dbtup::checkDeferredTriggersDuringPrepare(KeyReqStruct *req_struct,
799 DLList<TupTriggerData>& triggerList,
800 Operationrec* const regOperPtr,
801 bool disk)
802 {
803 jam();
804 TriggerPtr trigPtr;
805 triggerList.first(trigPtr);
806 while (trigPtr.i != RNIL)
807 {
808 jam();
809 if (trigPtr.p->monitorAllAttributes ||
810 trigPtr.p->attributeMask.overlaps(req_struct->changeMask))
811 {
812 jam();
813 switch(trigPtr.p->triggerType){
814 case TriggerType::SECONDARY_INDEX:
815 NoOfFiredTriggers::setDeferredUKBit(req_struct->num_fired_triggers);
816 break;
817 case TriggerType::FK_PARENT:
818 case TriggerType::FK_CHILD:
819 NoOfFiredTriggers::setDeferredFKBit(req_struct->num_fired_triggers);
820 break;
821 default:
822 ndbassert(false);
823 }
824 if (NoOfFiredTriggers::getDeferredAllSet(req_struct->num_fired_triggers))
825 return;
826 }
827 triggerList.next(trigPtr);
828 }
829 }
830
831 /* ---------------------------------------------------------------- */
832 /* --------------------- checkDeferredTriggers -------------------- */
833 /* */
834 /* Called before commit after an insert, delete, or update */
835 /* operation. Fetches before tuple for deletes and updates and */
836 /* after tuple for inserts and updates. */
837 /* Executes deferred triggers by sending FIRETRIGORD */
838 /* */
839 /* ---------------------------------------------------------------- */
checkDeferredTriggers(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)840 void Dbtup::checkDeferredTriggers(KeyReqStruct *req_struct,
841 Operationrec* regOperPtr,
842 Tablerec* regTablePtr,
843 bool disk)
844 {
845 jam();
846 Uint32 save_type = regOperPtr->op_type;
847 Tuple_header *save_ptr = req_struct->m_tuple_ptr;
848 DLList<TupTriggerData> * deferred_list = 0;
849 DLList<TupTriggerData> * constraint_list = 0;
850
851 switch (save_type) {
852 case ZUPDATE:
853 case ZINSERT:
854 req_struct->m_tuple_ptr =get_copy_tuple(®OperPtr->m_copy_tuple_location);
855 break;
856 }
857
858 /**
859 * Set correct operation type and fix change mask
860 * Note ALLOC is set in "orig" tuple
861 */
862 if (save_ptr->m_header_bits & Tuple_header::ALLOC) {
863 if (save_type == ZDELETE) {
864 // insert + delete = nothing
865 jam();
866 return;
867 goto end;
868 }
869 regOperPtr->op_type = ZINSERT;
870 }
871 else if (save_type == ZINSERT) {
872 /**
873 * Tuple was not created but last op is INSERT.
874 * This is possible only on DELETE + INSERT
875 */
876 regOperPtr->op_type = ZUPDATE;
877 }
878
879 switch(regOperPtr->op_type) {
880 case(ZINSERT):
881 jam();
882 deferred_list = ®TablePtr->deferredInsertTriggers;
883 constraint_list = ®TablePtr->afterInsertTriggers;
884 break;
885 case(ZDELETE):
886 jam();
887 deferred_list = ®TablePtr->deferredDeleteTriggers;
888 constraint_list = ®TablePtr->afterDeleteTriggers;
889 break;
890 case(ZUPDATE):
891 jam();
892 deferred_list = ®TablePtr->deferredUpdateTriggers;
893 constraint_list = ®TablePtr->afterUpdateTriggers;
894 break;
895 default:
896 ndbrequire(false);
897 break;
898 }
899
900 if (req_struct->m_deferred_constraints == false)
901 {
902 constraint_list = 0;
903 }
904
905 if (deferred_list->isEmpty() &&
906 (constraint_list == 0 || constraint_list->isEmpty()))
907 {
908 goto end;
909 }
910
911 /**
912 * Compute change-mask
913 */
914 set_commit_change_mask_info(regTablePtr, req_struct, regOperPtr);
915 if (!deferred_list->isEmpty())
916 {
917 fireDeferredTriggers(req_struct, * deferred_list, regOperPtr, disk);
918 }
919
920 if (constraint_list && !constraint_list->isEmpty())
921 {
922 fireDeferredConstraints(req_struct, * constraint_list, regOperPtr, disk);
923 }
924
925 end:
926 regOperPtr->op_type = save_type;
927 req_struct->m_tuple_ptr = save_ptr;
928 }//Dbtup::checkDeferredTriggers()
929
930 /* ---------------------------------------------------------------- */
931 /* --------------------- checkDetachedTriggers -------------------- */
932 /* */
933 /* Called at commit after an insert, delete, or update operation. */
934 /* Fetches before tuple for deletes and updates and */
935 /* after tuple for inserts and updates. */
936 /* Executes detached triggers by sending FIRETRIGORD */
937 /* */
938 /* ---------------------------------------------------------------- */
checkDetachedTriggers(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk,Uint32 diskPagePtrI)939 void Dbtup::checkDetachedTriggers(KeyReqStruct *req_struct,
940 Operationrec* regOperPtr,
941 Tablerec* regTablePtr,
942 bool disk,
943 Uint32 diskPagePtrI)
944 {
945 Uint32 save_type = regOperPtr->op_type;
946 Tuple_header *save_ptr = req_struct->m_tuple_ptr;
947
948 switch (save_type) {
949 case ZUPDATE:
950 case ZINSERT:
951 case ZREFRESH:
952 req_struct->m_tuple_ptr =get_copy_tuple(®OperPtr->m_copy_tuple_location);
953 break;
954 }
955
956 /**
957 * Set correct operation type and fix change mask
958 * Note ALLOC is set in "orig" tuple
959 */
960 if (save_ptr->m_header_bits & Tuple_header::ALLOC) {
961 if (save_type == ZDELETE) {
962 // insert + delete = nothing
963 jam();
964 return;
965 goto end;
966 }
967 else if (save_type != ZREFRESH)
968 {
969 regOperPtr->op_type = ZINSERT;
970 }
971 }
972 else if (save_type == ZINSERT) {
973 /**
974 * Tuple was not created but last op is INSERT.
975 * This is possible only on DELETE + INSERT
976 */
977 regOperPtr->op_type = ZUPDATE;
978 }
979
980 switch(regOperPtr->op_type) {
981 case(ZINSERT):
982 jam();
983 if (regTablePtr->subscriptionInsertTriggers.isEmpty()) {
984 // Table has no active triggers monitoring inserts at commit
985 jam();
986 goto end;
987 }
988
989 // If any fired immediate insert trigger then fetch after tuple
990 fireDetachedTriggers(req_struct,
991 regTablePtr->subscriptionInsertTriggers,
992 regOperPtr,
993 disk,
994 diskPagePtrI);
995 break;
996 case(ZDELETE):
997 jam();
998 if (regTablePtr->subscriptionDeleteTriggers.isEmpty()) {
999 // Table has no active triggers monitoring deletes at commit
1000 jam();
1001 goto end;
1002 }
1003
1004 // Execute any after delete triggers by sending
1005 // FIRETRIGORD with the before tuple
1006 fireDetachedTriggers(req_struct,
1007 regTablePtr->subscriptionDeleteTriggers,
1008 regOperPtr,
1009 disk,
1010 diskPagePtrI);
1011 break;
1012 case(ZUPDATE):
1013 jam();
1014 if (regTablePtr->subscriptionUpdateTriggers.isEmpty()) {
1015 // Table has no active triggers monitoring updates at commit
1016 jam();
1017 goto end;
1018 }
1019
1020 // If any fired immediate update trigger then fetch after tuple
1021 // and send two FIRETRIGORD one with before tuple and one with after tuple
1022 fireDetachedTriggers(req_struct,
1023 regTablePtr->subscriptionUpdateTriggers,
1024 regOperPtr,
1025 disk,
1026 diskPagePtrI);
1027 break;
1028 case ZREFRESH:
1029 jam();
1030 /* Depending on the Refresh scenario, fire Delete or Insert
1031 * triggers to simulate the effect of arriving at the tuple's
1032 * current state.
1033 */
1034 switch(regOperPtr->m_copy_tuple_location.m_file_no){
1035 case Operationrec::RF_SINGLE_NOT_EXIST:
1036 case Operationrec::RF_MULTI_NOT_EXIST:
1037 fireDetachedTriggers(req_struct,
1038 regTablePtr->subscriptionDeleteTriggers,
1039 regOperPtr,
1040 disk,
1041 diskPagePtrI);
1042 break;
1043 case Operationrec::RF_SINGLE_EXIST:
1044 case Operationrec::RF_MULTI_EXIST:
1045 fireDetachedTriggers(req_struct,
1046 regTablePtr->subscriptionInsertTriggers,
1047 regOperPtr,
1048 disk,
1049 diskPagePtrI);
1050 break;
1051 default:
1052 ndbrequire(false);
1053 }
1054 break;
1055 default:
1056 ndbrequire(false);
1057 break;
1058 }
1059
1060 end:
1061 regOperPtr->op_type = save_type;
1062 req_struct->m_tuple_ptr = save_ptr;
1063 }
1064
1065 static
1066 bool
is_constraint(const Dbtup::TupTriggerData * trigPtr)1067 is_constraint(const Dbtup::TupTriggerData * trigPtr)
1068 {
1069 return
1070 (trigPtr->triggerType == TriggerType::SECONDARY_INDEX) ||
1071 (trigPtr->triggerType == TriggerType::FK_PARENT) ||
1072 (trigPtr->triggerType == TriggerType::FK_CHILD);
1073 }
1074
1075 void
fireImmediateTriggers(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)1076 Dbtup::fireImmediateTriggers(KeyReqStruct *req_struct,
1077 DLList<TupTriggerData>& triggerList,
1078 Operationrec* const regOperPtr,
1079 bool disk)
1080 {
1081 TriggerPtr trigPtr;
1082 triggerList.first(trigPtr);
1083 while (trigPtr.i != RNIL) {
1084 jam();
1085 if (trigPtr.p->monitorAllAttributes ||
1086 trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
1087 jam();
1088
1089 if (req_struct->m_when == KRS_PREPARE &&
1090 req_struct->m_deferred_constraints &&
1091 is_constraint(trigPtr.p))
1092 {
1093 switch(trigPtr.p->triggerType){
1094 case TriggerType::SECONDARY_INDEX:
1095 NoOfFiredTriggers::setDeferredUKBit(req_struct->num_fired_triggers);
1096 break;
1097 case TriggerType::FK_PARENT:
1098 case TriggerType::FK_CHILD:
1099 NoOfFiredTriggers::setDeferredFKBit(req_struct->num_fired_triggers);
1100 break;
1101 default:
1102 ndbassert(false);
1103 }
1104 }
1105 else
1106 {
1107 executeTrigger(req_struct,
1108 trigPtr.p,
1109 regOperPtr,
1110 disk);
1111 }
1112 }
1113 triggerList.next(trigPtr);
1114 }//while
1115 }//Dbtup::fireImmediateTriggers()
1116
1117 void
fireDeferredConstraints(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)1118 Dbtup::fireDeferredConstraints(KeyReqStruct *req_struct,
1119 DLList<TupTriggerData>& triggerList,
1120 Operationrec* const regOperPtr,
1121 bool disk)
1122 {
1123 TriggerPtr trigPtr;
1124 triggerList.first(trigPtr);
1125 while (trigPtr.i != RNIL) {
1126 jam();
1127 if (trigPtr.p->monitorAllAttributes ||
1128 trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
1129 jam();
1130 executeTrigger(req_struct,
1131 trigPtr.p,
1132 regOperPtr,
1133 disk);
1134 }//if
1135 triggerList.next(trigPtr);
1136 }//while
1137 }//Dbtup::fireDeferredTriggers()
1138
1139 void
fireDeferredTriggers(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)1140 Dbtup::fireDeferredTriggers(KeyReqStruct *req_struct,
1141 DLList<TupTriggerData>& triggerList,
1142 Operationrec* const regOperPtr,
1143 bool disk)
1144 {
1145 TriggerPtr trigPtr;
1146 triggerList.first(trigPtr);
1147 while (trigPtr.i != RNIL) {
1148 jam();
1149 if (trigPtr.p->monitorAllAttributes ||
1150 trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
1151 jam();
1152 executeTrigger(req_struct,
1153 trigPtr.p,
1154 regOperPtr,
1155 disk);
1156 }//if
1157 triggerList.next(trigPtr);
1158 }//while
1159 }//Dbtup::fireDeferredTriggers()
1160
1161 void
fireDetachedTriggers(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk,Uint32 diskPagePtrI)1162 Dbtup::fireDetachedTriggers(KeyReqStruct *req_struct,
1163 DLList<TupTriggerData>& triggerList,
1164 Operationrec* const regOperPtr,
1165 bool disk,
1166 Uint32 diskPagePtrI)
1167 {
1168
1169 TriggerPtr trigPtr;
1170
1171 /**
1172 * Set disk page
1173 */
1174 req_struct->m_disk_page_ptr.i = diskPagePtrI;
1175
1176 ndbrequire(regOperPtr->is_first_operation());
1177 triggerList.first(trigPtr);
1178 while (trigPtr.i != RNIL) {
1179 jam();
1180 if ((trigPtr.p->monitorReplicas ||
1181 regOperPtr->op_struct.bit_field.primary_replica) &&
1182 (trigPtr.p->monitorAllAttributes ||
1183 trigPtr.p->attributeMask.overlaps(req_struct->changeMask))) {
1184 jam();
1185 executeTrigger(req_struct,
1186 trigPtr.p,
1187 regOperPtr,
1188 disk);
1189 }
1190 triggerList.next(trigPtr);
1191 }
1192 }
1193
1194 bool
check_fire_trigger(const Fragrecord * fragPtrP,const TupTriggerData * trigPtrP,const KeyReqStruct * req_struct,const Operationrec * regOperPtr) const1195 Dbtup::check_fire_trigger(const Fragrecord * fragPtrP,
1196 const TupTriggerData* trigPtrP,
1197 const KeyReqStruct * req_struct,
1198 const Operationrec * regOperPtr) const
1199 {
1200 jam();
1201
1202 if (trigPtrP->triggerType == TriggerType::SUBSCRIPTION_BEFORE)
1203 {
1204 if (!check_fire_suma(req_struct, regOperPtr, fragPtrP))
1205 return false;
1206 return true;
1207 }
1208
1209 switch(fragPtrP->fragStatus){
1210 case Fragrecord::FS_REORG_NEW:
1211 jam();
1212 return false;
1213 case Fragrecord::FS_REORG_COMMIT:
1214 case Fragrecord::FS_REORG_COMPLETE:
1215 return req_struct->m_reorg == ScanFragReq::REORG_ALL;
1216 default:
1217 return true;
1218 }
1219 }
1220
1221 bool
check_fire_reorg(const KeyReqStruct * req_struct,Fragrecord::FragState state) const1222 Dbtup::check_fire_reorg(const KeyReqStruct *req_struct,
1223 Fragrecord::FragState state) const
1224 {
1225 Uint32 flag = req_struct->m_reorg;
1226 switch(state){
1227 case Fragrecord::FS_ONLINE:
1228 case Fragrecord::FS_REORG_COMMIT_NEW:
1229 case Fragrecord::FS_REORG_COMPLETE_NEW:
1230 jam();
1231 if (flag == ScanFragReq::REORG_MOVED)
1232 {
1233 jam();
1234 return true;
1235 }
1236 return false;
1237 case Fragrecord::FS_REORG_NEW:
1238 case Fragrecord::FS_REORG_COMMIT:
1239 case Fragrecord::FS_REORG_COMPLETE:
1240 default:
1241 jam();
1242 return false;
1243 }
1244 }
1245
1246 bool
check_fire_suma(const KeyReqStruct * req_struct,const Operationrec * opPtrP,const Fragrecord * regFragPtrP) const1247 Dbtup::check_fire_suma(const KeyReqStruct *req_struct,
1248 const Operationrec* opPtrP,
1249 const Fragrecord* regFragPtrP) const
1250 {
1251 Ptr<Tablerec> tablePtr;
1252 tablePtr.i = regFragPtrP->fragTableId;
1253 Fragrecord::FragState state = regFragPtrP->fragStatus;
1254 Uint32 gci_hi = req_struct->gci_hi;
1255 Uint32 flag = opPtrP->op_struct.bit_field.m_reorg;
1256
1257 switch(state){
1258 case Fragrecord::FS_FREE:
1259 ndbassert(false);
1260 return false;
1261 case Fragrecord::FS_ONLINE:
1262 jam();
1263 return true;
1264 case Fragrecord::FS_REORG_NEW:
1265 jam();
1266 return false;
1267 case Fragrecord::FS_REORG_COMMIT_NEW:
1268 jam();
1269 return false;
1270 case Fragrecord::FS_REORG_COMPLETE_NEW:
1271 jam();
1272 return true;
1273 case Fragrecord::FS_REORG_COMMIT:
1274 jam();
1275 return true;
1276 case Fragrecord::FS_REORG_COMPLETE:
1277 jam();
1278 if (flag != ScanFragReq::REORG_NOT_MOVED)
1279 {
1280 jam();
1281 return true;
1282 }
1283 break;
1284 }
1285
1286 ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
1287 if (gci_hi < tablePtr.p->m_reorg_suma_filter.m_gci_hi)
1288 {
1289 jam();
1290 return true;
1291 }
1292
1293 return false;
1294 }
1295
1296 Uint32
getOldTriggerId(const TupTriggerData * trigPtrP,Uint32 op_type)1297 Dbtup::getOldTriggerId(const TupTriggerData* trigPtrP,
1298 Uint32 op_type)
1299 {
1300 switch(op_type){
1301 case ZINSERT:
1302 return trigPtrP->oldTriggerIds[0];
1303 case ZUPDATE:
1304 return trigPtrP->oldTriggerIds[1];
1305 case ZDELETE:
1306 return trigPtrP->oldTriggerIds[2];
1307 }
1308 ndbrequire(false);
1309 return RNIL;
1310 }
1311
1312 #define ZOUT_OF_LONG_SIGNAL_MEMORY_IN_TRIGGER 312
1313
executeTrigger(KeyReqStruct * req_struct,TupTriggerData * const trigPtr,Operationrec * const regOperPtr,bool disk)1314 void Dbtup::executeTrigger(KeyReqStruct *req_struct,
1315 TupTriggerData* const trigPtr,
1316 Operationrec* const regOperPtr,
1317 bool disk)
1318 {
1319 Signal* signal= req_struct->signal;
1320 BlockReference ref = trigPtr->m_receiverRef;
1321 Uint32* const keyBuffer = &cinBuffer[0];
1322 Uint32* const afterBuffer = &coutBuffer[0];
1323 Uint32* const beforeBuffer = &clogMemBuffer[0];
1324 Uint32 triggerType = trigPtr->triggerType;
1325
1326 if ((triggerType == TriggerType::FK_PARENT ||
1327 triggerType == TriggerType::FK_CHILD) &&
1328 regOperPtr->op_struct.bit_field.m_disable_fk_checks)
1329 {
1330 jam();
1331 return;
1332 }
1333
1334 Uint32 noPrimKey, noAfterWords, noBeforeWords;
1335 FragrecordPtr regFragPtr;
1336 regFragPtr.i= regOperPtr->fragmentPtr;
1337 ptrCheckGuard(regFragPtr, cnoOfFragrec, fragrecord);
1338 Fragrecord::FragState fragstatus = regFragPtr.p->fragStatus;
1339
1340 if (refToMain(ref) == BACKUP)
1341 {
1342 jam();
1343 if (isNdbMtLqh())
1344 {
1345 goto out;
1346 }
1347
1348 /*
1349 In order for the implementation of BACKUP to work even when changing
1350 primaries in the middle of the backup we need to set the trigger on
1351 all replicas. This check checks whether this is the node where this
1352 trigger should be fired. The check should preferably have been put
1353 completely in the BACKUP block but it was about five times simpler
1354 to put it here and also much faster for the backup (small overhead
1355 for everybody else.
1356 */
1357 signal->theData[0] = trigPtr->triggerId;
1358 signal->theData[1] = regFragPtr.p->fragmentId;
1359 EXECUTE_DIRECT(BACKUP, GSN_BACKUP_TRIG_REQ, signal, 2);
1360 jamEntry();
1361 if (signal->theData[0] == 0) {
1362 jam();
1363 return;
1364 }
1365 out:
1366 (void)1;
1367 }
1368 else if (unlikely(triggerType == TriggerType::REORG_TRIGGER))
1369 {
1370 if (!check_fire_reorg(req_struct, fragstatus))
1371 return;
1372 }
1373 else if (unlikely(regFragPtr.p->fragStatus != Fragrecord::FS_ONLINE))
1374 {
1375 if (!check_fire_trigger(regFragPtr.p, trigPtr, req_struct, regOperPtr))
1376 return;
1377 }
1378
1379 if (!readTriggerInfo(trigPtr,
1380 regOperPtr,
1381 req_struct,
1382 regFragPtr.p,
1383 keyBuffer,
1384 noPrimKey,
1385 afterBuffer,
1386 noAfterWords,
1387 beforeBuffer,
1388 noBeforeWords,
1389 disk)) {
1390 jam();
1391 return;
1392 }
1393
1394 //--------------------------------------------------------------------
1395 // Now all data for this trigger has been read. It is now time to send
1396 // the trigger information consisting of two or three sets of TRIG_
1397 // ATTRINFO signals and one FIRE_TRIG_ORD signal.
1398 // We start by setting common header info for all TRIG_ATTRINFO signals.
1399 //--------------------------------------------------------------------
1400 bool executeDirect;
1401 bool longsignal = false;
1402 bool detached = false;
1403 Uint32 triggerId = trigPtr->triggerId;
1404 TrigAttrInfo* const trigAttrInfo = (TrigAttrInfo *)signal->getDataPtrSend();
1405 trigAttrInfo->setConnectionPtr(req_struct->TC_index);
1406 trigAttrInfo->setTriggerId(trigPtr->triggerId);
1407
1408 switch(triggerType) {
1409 case (TriggerType::SECONDARY_INDEX):
1410 {
1411 jam();
1412 /**
1413 * Handle stupid 6.3 which uses one triggerId per operation type
1414 */
1415 Uint32 node = refToNode(req_struct->TC_ref);
1416 if (unlikely(node && getNodeInfo(node).m_version < MAKE_VERSION(6,4,0)))
1417 {
1418 jam();
1419 triggerId = getOldTriggerId(trigPtr, regOperPtr->op_type);
1420 trigAttrInfo->setTriggerId(triggerId);
1421 }
1422 // fall-through
1423 }
1424 case (TriggerType::REORG_TRIGGER):
1425 case (TriggerType::FK_PARENT):
1426 case (TriggerType::FK_CHILD):
1427 jam();
1428 ref = req_struct->TC_ref;
1429 executeDirect = false;
1430 longsignal = ndbd_long_fire_trig_ord(getNodeInfo(refToNode(ref)).m_version);
1431 break;
1432 case (TriggerType::SUBSCRIPTION):
1433 case (TriggerType::SUBSCRIPTION_BEFORE):
1434 jam();
1435 // Since only backup uses subscription triggers we send to backup directly for now
1436 ref = trigPtr->m_receiverRef;
1437 // executeDirect = !isNdbMtLqh() || (refToMain(ref) != SUMA);
1438 executeDirect = refToInstance(ref) == instance();
1439
1440 // If we can do execute direct, lets do that, else do long signal (only local node)
1441 longsignal = !executeDirect;
1442 ndbassert(refToNode(ref) == 0 || refToNode(ref) == getOwnNodeId());
1443 detached = true;
1444 break;
1445 case (TriggerType::READ_ONLY_CONSTRAINT):
1446 terrorCode = ZREAD_ONLY_CONSTRAINT_VIOLATION;
1447 // XXX should return status and abort the rest
1448 return;
1449 default:
1450 ndbrequire(false);
1451 executeDirect= false; // remove warning
1452 }//switch
1453
1454
1455 if (ERROR_INSERTED(4030))
1456 {
1457 terrorCode = ZREAD_ONLY_CONSTRAINT_VIOLATION;
1458 // XXX should return status and abort the rest
1459 return;
1460 }
1461
1462 if (triggerType == TriggerType::SECONDARY_INDEX &&
1463 req_struct->m_when != KRS_PREPARE)
1464 {
1465 ndbrequire(req_struct->m_deferred_constraints);
1466 if (req_struct->m_when == KRS_UK_PRE_COMMIT0)
1467 {
1468 switch(regOperPtr->op_type){
1469 case ZINSERT:
1470 NoOfFiredTriggers::setDeferredUKBit(req_struct->num_fired_triggers);
1471 return;
1472 break;
1473 case ZUPDATE:
1474 NoOfFiredTriggers::setDeferredUKBit(req_struct->num_fired_triggers);
1475 noAfterWords = 0;
1476 break;
1477 case ZDELETE:
1478 break;
1479 default:
1480 ndbrequire(false);
1481 }
1482 }
1483 else if (req_struct->m_when == KRS_UK_PRE_COMMIT1)
1484 {
1485 switch(regOperPtr->op_type){
1486 case ZINSERT:
1487 break;
1488 case ZUPDATE:
1489 noBeforeWords = 0;
1490 break;
1491 case ZDELETE:
1492 return;
1493 default:
1494 ndbrequire(false);
1495 }
1496 }
1497 else
1498 {
1499 ndbassert(req_struct->m_when == KRS_FK_PRE_COMMIT);
1500 return;
1501 }
1502 }
1503
1504 if ((triggerType == TriggerType::FK_PARENT ||
1505 triggerType == TriggerType::FK_CHILD) &&
1506 req_struct->m_when != KRS_PREPARE)
1507 {
1508 if (req_struct->m_when != KRS_FK_PRE_COMMIT)
1509 {
1510 return;
1511 }
1512 }
1513
1514 req_struct->num_fired_triggers++;
1515
1516 if (longsignal == false)
1517 {
1518 jam();
1519
1520 trigAttrInfo->setAttrInfoType(TrigAttrInfo::PRIMARY_KEY);
1521 sendTrigAttrInfo(signal, keyBuffer, noPrimKey, executeDirect, ref);
1522
1523 switch(regOperPtr->op_type) {
1524 case(ZINSERT):
1525 is_insert:
1526 jam();
1527 // Send AttrInfo signals with new attribute values
1528 trigAttrInfo->setAttrInfoType(TrigAttrInfo::AFTER_VALUES);
1529 sendTrigAttrInfo(signal, afterBuffer, noAfterWords, executeDirect, ref);
1530 break;
1531 case(ZDELETE):
1532 is_delete:
1533 if (trigPtr->sendBeforeValues) {
1534 jam();
1535 trigAttrInfo->setAttrInfoType(TrigAttrInfo::BEFORE_VALUES);
1536 sendTrigAttrInfo(signal, beforeBuffer, noBeforeWords, executeDirect,ref);
1537 }
1538 break;
1539 case(ZUPDATE):
1540 jam();
1541 if (trigPtr->sendBeforeValues) {
1542 jam();
1543 trigAttrInfo->setAttrInfoType(TrigAttrInfo::BEFORE_VALUES);
1544 sendTrigAttrInfo(signal, beforeBuffer, noBeforeWords, executeDirect,ref);
1545 }
1546 trigAttrInfo->setAttrInfoType(TrigAttrInfo::AFTER_VALUES);
1547 sendTrigAttrInfo(signal, afterBuffer, noAfterWords, executeDirect, ref);
1548 break;
1549 case ZREFRESH:
1550 jam();
1551 /* Reuse Insert/Delete trigger firing code as necessary */
1552 switch(regOperPtr->m_copy_tuple_location.m_file_no){
1553 case Operationrec::RF_SINGLE_NOT_EXIST:
1554 jam();
1555 case Operationrec::RF_MULTI_NOT_EXIST:
1556 jam();
1557 goto is_delete;
1558 case Operationrec::RF_SINGLE_EXIST:
1559 jam();
1560 case Operationrec::RF_MULTI_EXIST:
1561 jam();
1562 goto is_insert;
1563 default:
1564 ndbrequire(false);
1565 }
1566 default:
1567 ndbrequire(false);
1568 }
1569 }
1570
1571 /**
1572 * sendFireTrigOrd
1573 */
1574 FireTrigOrd* const fireTrigOrd = (FireTrigOrd *)signal->getDataPtrSend();
1575
1576 fireTrigOrd->setConnectionPtr(req_struct->TC_index);
1577 fireTrigOrd->setTriggerId(triggerId);
1578 fireTrigOrd->fragId= regFragPtr.p->fragmentId;
1579
1580 switch(regOperPtr->op_type) {
1581 case(ZINSERT):
1582 jam();
1583 fireTrigOrd->m_triggerEvent = TriggerEvent::TE_INSERT;
1584 break;
1585 case(ZUPDATE):
1586 jam();
1587 fireTrigOrd->m_triggerEvent = TriggerEvent::TE_UPDATE;
1588 break;
1589 case(ZDELETE):
1590 jam();
1591 fireTrigOrd->m_triggerEvent = TriggerEvent::TE_DELETE;
1592 break;
1593 case ZREFRESH:
1594 jam();
1595 switch(regOperPtr->m_copy_tuple_location.m_file_no){
1596 case Operationrec::RF_SINGLE_NOT_EXIST:
1597 jam();
1598 case Operationrec::RF_MULTI_NOT_EXIST:
1599 jam();
1600 fireTrigOrd->m_triggerEvent = TriggerEvent::TE_DELETE;
1601 break;
1602 case Operationrec::RF_SINGLE_EXIST:
1603 jam();
1604 case Operationrec::RF_MULTI_EXIST:
1605 jam();
1606 fireTrigOrd->m_triggerEvent = TriggerEvent::TE_INSERT;
1607 break;
1608 default:
1609 ndbrequire(false);
1610 }
1611 break;
1612 default:
1613 ndbrequire(false);
1614 break;
1615 }
1616
1617 fireTrigOrd->setNoOfPrimaryKeyWords(noPrimKey);
1618 fireTrigOrd->setNoOfBeforeValueWords(noBeforeWords);
1619 fireTrigOrd->setNoOfAfterValueWords(noAfterWords);
1620
1621 LinearSectionPtr ptr[3];
1622 ptr[0].p = keyBuffer;
1623 ptr[0].sz = noPrimKey;
1624 ptr[1].p = beforeBuffer;
1625 ptr[1].sz = noBeforeWords;
1626 ptr[2].p = afterBuffer;
1627 ptr[2].sz = noAfterWords;
1628
1629 SectionHandle handle(this);
1630 if (longsignal && !detached && !import(&handle, ptr, 3))
1631 {
1632 jam();
1633 terrorCode = ZOUT_OF_LONG_SIGNAL_MEMORY_IN_TRIGGER;
1634 return;
1635 }
1636
1637 switch(trigPtr->triggerType) {
1638 case (TriggerType::SECONDARY_INDEX):
1639 case (TriggerType::REORG_TRIGGER):
1640 case (TriggerType::FK_PARENT):
1641 case (TriggerType::FK_CHILD):
1642 jam();
1643 fireTrigOrd->m_triggerType = trigPtr->triggerType;
1644 fireTrigOrd->m_transId1 = req_struct->trans_id1;
1645 fireTrigOrd->m_transId2 = req_struct->trans_id2;
1646 if (longsignal)
1647 {
1648 jam();
1649 sendSignal(req_struct->TC_ref, GSN_FIRE_TRIG_ORD,
1650 signal, FireTrigOrd::SignalLength, JBB, &handle);
1651 }
1652 else
1653 {
1654 jam();
1655 sendSignal(req_struct->TC_ref, GSN_FIRE_TRIG_ORD,
1656 signal, FireTrigOrd::SignalLength, JBB);
1657 }
1658 break;
1659 case (TriggerType::SUBSCRIPTION_BEFORE): // Only Suma
1660 jam();
1661 fireTrigOrd->m_transId1 = req_struct->trans_id1;
1662 fireTrigOrd->m_transId2 = req_struct->trans_id2;
1663 fireTrigOrd->setGCI(req_struct->gci_hi);
1664 fireTrigOrd->setHashValue(req_struct->hash_value);
1665 fireTrigOrd->m_any_value = regOperPtr->m_any_value;
1666 fireTrigOrd->m_gci_lo = req_struct->gci_lo;
1667 if (executeDirect)
1668 {
1669 jam();
1670 EXECUTE_DIRECT(refToMain(ref),
1671 GSN_FIRE_TRIG_ORD,
1672 signal,
1673 FireTrigOrd::SignalLengthSuma);
1674 jamEntry();
1675 }
1676 else
1677 {
1678 ndbassert(longsignal);
1679 LinearSectionPtr ptr[3];
1680 ptr[0].p = keyBuffer;
1681 ptr[0].sz = noPrimKey;
1682 ptr[1].p = beforeBuffer;
1683 ptr[1].sz = noBeforeWords;
1684 ptr[2].p = afterBuffer;
1685 ptr[2].sz = noAfterWords;
1686 if (refToMain(ref) == SUMA && (refToInstance(ref) != instance()))
1687 {
1688 jam();
1689 ndbmtd_buffer_suma_trigger(signal, FireTrigOrd::SignalLengthSuma, ptr);
1690 }
1691 else
1692 {
1693 jam();
1694 sendSignal(ref, GSN_FIRE_TRIG_ORD,
1695 signal, FireTrigOrd::SignalLengthSuma, JBB, ptr, 3);
1696 }
1697 }
1698 break;
1699 case (TriggerType::SUBSCRIPTION):
1700 jam();
1701 // Since only backup uses subscription triggers we
1702 // send to backup directly for now
1703 fireTrigOrd->setGCI(req_struct->gci_hi);
1704
1705 if (executeDirect)
1706 {
1707 jam();
1708 EXECUTE_DIRECT(refToMain(ref),
1709 GSN_FIRE_TRIG_ORD,
1710 signal,
1711 FireTrigOrd::SignalWithGCILength);
1712 jamEntry();
1713 }
1714 else
1715 {
1716 jam();
1717 // Todo send onlu before/after depending on BACKUP REDO/UNDO
1718 ndbassert(longsignal);
1719 LinearSectionPtr ptr[3];
1720 ptr[0].p = keyBuffer;
1721 ptr[0].sz = noPrimKey;
1722 ptr[1].p = beforeBuffer;
1723 ptr[1].sz = noBeforeWords;
1724 ptr[2].p = afterBuffer;
1725 ptr[2].sz = noAfterWords;
1726 sendSignal(ref, GSN_FIRE_TRIG_ORD,
1727 signal, FireTrigOrd::SignalWithGCILength, JBB, ptr, 3);
1728 }
1729 break;
1730 default:
1731 ndbrequire(false);
1732 break;
1733 }
1734 }
1735
setAttrIds(Bitmask<MAXNROFATTRIBUTESINWORDS> & attributeMask,Uint32 no_of_attributes,Uint32 * inBuffer)1736 Uint32 Dbtup::setAttrIds(Bitmask<MAXNROFATTRIBUTESINWORDS>& attributeMask,
1737 Uint32 no_of_attributes,
1738 Uint32* inBuffer)
1739 {
1740 Uint32 bufIndx = 0;
1741 jam();
1742 for (Uint32 i = 0; i < no_of_attributes; i++)
1743 {
1744 if (attributeMask.get(i))
1745 {
1746 jamLine(i);
1747 AttributeHeader::init(&inBuffer[bufIndx++], i, 0);
1748 }
1749 }
1750 jam();
1751 return bufIndx;
1752 }
1753
readTriggerInfo(TupTriggerData * const trigPtr,Operationrec * const regOperPtr,KeyReqStruct * req_struct,Fragrecord * const regFragPtr,Uint32 * const keyBuffer,Uint32 & noPrimKey,Uint32 * const afterBuffer,Uint32 & noAfterWords,Uint32 * const beforeBuffer,Uint32 & noBeforeWords,bool disk)1754 bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr,
1755 Operationrec* const regOperPtr,
1756 KeyReqStruct *req_struct,
1757 Fragrecord* const regFragPtr,
1758 Uint32* const keyBuffer,
1759 Uint32& noPrimKey,
1760 Uint32* const afterBuffer,
1761 Uint32& noAfterWords,
1762 Uint32* const beforeBuffer,
1763 Uint32& noBeforeWords,
1764 bool disk)
1765 {
1766 noAfterWords = 0;
1767 noBeforeWords = 0;
1768 Uint32 readBuffer[MAX_ATTRIBUTES_IN_TABLE];
1769
1770 //---------------------------------------------------------------------------
1771 // Set-up variables needed by readAttributes operPtr.p, tabptr.p
1772 //---------------------------------------------------------------------------
1773 Ptr<Tablerec> tabptr;
1774 Ptr<Operationrec> operPtr;
1775 operPtr.p = regOperPtr;
1776 tabptr.i = regFragPtr->fragTableId;
1777 ptrCheckGuard(tabptr, cnoOfTablerec, tablerec);
1778
1779 Tablerec* const regTabPtr = tabptr.p;
1780 Uint32 num_attr= regTabPtr->m_no_of_attributes;
1781 Uint32 descr_start= regTabPtr->tabDescriptor;
1782 ndbrequire(descr_start + (num_attr << ZAD_LOG_SIZE) <= cnoOfTabDescrRec);
1783
1784 req_struct->tablePtrP = regTabPtr;
1785 req_struct->operPtrP = regOperPtr;
1786 req_struct->check_offset[MM]= regTabPtr->get_check_offset(MM);
1787 req_struct->check_offset[DD]= regTabPtr->get_check_offset(DD);
1788 req_struct->attr_descr= &tableDescriptor[descr_start];
1789
1790 if ((regOperPtr->op_struct.bit_field.m_physical_only_op == 1) &&
1791 (refToMain(trigPtr->m_receiverRef) == SUMA ||
1792 refToMain(trigPtr->m_receiverRef) == BACKUP))
1793 {
1794 /* Operations that have no logical effect need not be backed up
1795 * or sent as an event. Eg. OPTIMIZE TABLE is performed as a
1796 * ZUPDATE operation on table records, moving the varpart
1797 * column-values between pages, to be storage-effective.
1798 */
1799 Uint32 changed_attribs = 0;
1800 for (Uint32 i = 0; i < regTabPtr->m_no_of_attributes; i++) {
1801 jam();
1802 if (req_struct->changeMask.get(i)) {
1803 jam();
1804 changed_attribs++;
1805 }
1806 }
1807 ndbrequire(changed_attribs == 0);
1808 return false;
1809 }
1810
1811 //--------------------------------------------------------------------
1812 // Read Primary Key Values
1813 //--------------------------------------------------------------------
1814 Tuple_header *save0= req_struct->m_tuple_ptr;
1815 if (regOperPtr->op_type == ZDELETE &&
1816 !regOperPtr->is_first_operation())
1817 {
1818 jam();
1819 req_struct->m_tuple_ptr=
1820 get_copy_tuple(&req_struct->prevOpPtr.p->m_copy_tuple_location);
1821 }
1822
1823 if (regTabPtr->need_expand(disk))
1824 prepare_read(req_struct, regTabPtr, disk);
1825
1826 int ret = readAttributes(req_struct,
1827 &tableDescriptor[regTabPtr->readKeyArray].tabDescr,
1828 regTabPtr->noOfKeyAttr,
1829 keyBuffer,
1830 ZATTR_BUFFER_SIZE,
1831 false);
1832 ndbrequire(ret >= 0);
1833 noPrimKey= ret;
1834
1835 req_struct->m_tuple_ptr = save0;
1836
1837 Uint32 numAttrsToRead;
1838 if ((regOperPtr->op_type == ZUPDATE) &&
1839 (trigPtr->sendOnlyChangedAttributes)) {
1840 jam();
1841 //--------------------------------------------------------------------
1842 // Update that sends only changed information
1843 //--------------------------------------------------------------------
1844 Bitmask<MAXNROFATTRIBUTESINWORDS> attributeMask;
1845 attributeMask = trigPtr->attributeMask;
1846 attributeMask.bitAND(req_struct->changeMask);
1847 numAttrsToRead = setAttrIds(attributeMask, regTabPtr->m_no_of_attributes,
1848 &readBuffer[0]);
1849
1850 } else if ((regOperPtr->op_type == ZDELETE) &&
1851 (!trigPtr->sendBeforeValues)) {
1852 jam();
1853 //--------------------------------------------------------------------
1854 // Delete without sending before values only read Primary Key
1855 //--------------------------------------------------------------------
1856 return true;
1857 } else if (regOperPtr->op_type != ZREFRESH){
1858 jam();
1859 //--------------------------------------------------------------------
1860 // All others send all attributes that are monitored, except:
1861 // Omit unchanged blob inlines on update i.e.
1862 // attributeMask & ~ (blobAttributeMask & ~ changeMask)
1863 //--------------------------------------------------------------------
1864 Bitmask<MAXNROFATTRIBUTESINWORDS> attributeMask;
1865 attributeMask = trigPtr->attributeMask;
1866 if (regOperPtr->op_type == ZUPDATE) {
1867 Bitmask<MAXNROFATTRIBUTESINWORDS> tmpMask = regTabPtr->blobAttributeMask;
1868 tmpMask.bitANDC(req_struct->changeMask);
1869 attributeMask.bitANDC(tmpMask);
1870 }
1871 numAttrsToRead = setAttrIds(attributeMask, regTabPtr->m_no_of_attributes,
1872 &readBuffer[0]);
1873 }
1874 else
1875 {
1876 jam();
1877 ndbassert(regOperPtr->op_type == ZREFRESH);
1878 /* Refresh specific before/after value hacks */
1879 switch(regOperPtr->m_copy_tuple_location.m_file_no){
1880 case Operationrec::RF_SINGLE_NOT_EXIST:
1881 case Operationrec::RF_MULTI_NOT_EXIST:
1882 return true; // generate ZDELETE...no before values
1883 case Operationrec::RF_SINGLE_EXIST:
1884 case Operationrec::RF_MULTI_EXIST:
1885 // generate ZINSERT...all after values
1886 numAttrsToRead = setAttrIds(trigPtr->attributeMask,
1887 regTabPtr->m_no_of_attributes,
1888 &readBuffer[0]);
1889 break;
1890 default:
1891 ndbrequire(false);
1892 }
1893 }
1894
1895 ndbrequire(numAttrsToRead <= MAX_ATTRIBUTES_IN_TABLE);
1896 //--------------------------------------------------------------------
1897 // Read Main tuple values
1898 //--------------------------------------------------------------------
1899 if (regOperPtr->op_type != ZDELETE)
1900 {
1901 jam();
1902 int ret = readAttributes(req_struct,
1903 &readBuffer[0],
1904 numAttrsToRead,
1905 afterBuffer,
1906 ZATTR_BUFFER_SIZE,
1907 false);
1908 ndbrequire(ret >= 0);
1909 noAfterWords= ret;
1910 } else {
1911 jam();
1912 noAfterWords = 0;
1913 }
1914
1915 //--------------------------------------------------------------------
1916 // Read Copy tuple values for UPDATE's
1917 //--------------------------------------------------------------------
1918 // Initialise pagep and tuple offset for read of copy tuple
1919 //--------------------------------------------------------------------
1920 if ((regOperPtr->op_type == ZUPDATE ||
1921 regOperPtr->op_type == ZDELETE) &&
1922 (trigPtr->sendBeforeValues)) {
1923 jam();
1924
1925 Tuple_header *save= req_struct->m_tuple_ptr;
1926 PagePtr tmp;
1927 if(regOperPtr->is_first_operation())
1928 {
1929 Uint32 *ptr= get_ptr(&tmp, ®OperPtr->m_tuple_location, regTabPtr);
1930 req_struct->m_tuple_ptr= (Tuple_header*)ptr;
1931 }
1932 else
1933 {
1934 req_struct->m_tuple_ptr =
1935 get_copy_tuple(&req_struct->prevOpPtr.p->m_copy_tuple_location);
1936 }
1937
1938 if (regTabPtr->need_expand(disk))
1939 prepare_read(req_struct, regTabPtr, disk);
1940
1941 int ret = readAttributes(req_struct,
1942 &readBuffer[0],
1943 numAttrsToRead,
1944 beforeBuffer,
1945 ZATTR_BUFFER_SIZE,
1946 false);
1947 req_struct->m_tuple_ptr= save;
1948 ndbrequire(ret >= 0);
1949 noBeforeWords = ret;
1950 if (refToMain(trigPtr->m_receiverRef) != SUMA &&
1951 (noAfterWords == noBeforeWords) &&
1952 (memcmp(afterBuffer, beforeBuffer, noAfterWords << 2) == 0)) {
1953 //--------------------------------------------------------------------
1954 // Although a trigger was fired it was not necessary since the old
1955 // value and the new value was exactly the same
1956 //--------------------------------------------------------------------
1957 jam();
1958 //XXX does this work with collations?
1959 return false;
1960 }
1961 }
1962 return true;
1963 }
1964
sendTrigAttrInfo(Signal * signal,Uint32 * data,Uint32 dataLen,bool executeDirect,BlockReference receiverReference)1965 void Dbtup::sendTrigAttrInfo(Signal* signal,
1966 Uint32* data,
1967 Uint32 dataLen,
1968 bool executeDirect,
1969 BlockReference receiverReference)
1970 {
1971 TrigAttrInfo* const trigAttrInfo = (TrigAttrInfo *)signal->getDataPtrSend();
1972 Uint32 sigLen;
1973 Uint32 dataIndex = 0;
1974 do {
1975 sigLen = dataLen - dataIndex;
1976 if (sigLen > TrigAttrInfo::DataLength) {
1977 jam();
1978 sigLen = TrigAttrInfo::DataLength;
1979 }
1980 MEMCOPY_NO_WORDS(trigAttrInfo->getData(),
1981 data + dataIndex,
1982 sigLen);
1983 if (executeDirect) {
1984 jam();
1985 EXECUTE_DIRECT(refToMain(receiverReference),
1986 GSN_TRIG_ATTRINFO,
1987 signal,
1988 TrigAttrInfo::StaticLength + sigLen);
1989 jamEntry();
1990 } else {
1991 jam();
1992 sendSignal(receiverReference,
1993 GSN_TRIG_ATTRINFO,
1994 signal,
1995 TrigAttrInfo::StaticLength + sigLen,
1996 JBB);
1997 }
1998 dataIndex += sigLen;
1999 } while (dataLen != dataIndex);
2000 }
2001
2002 /*
2003 * Ordered index triggers.
2004 *
2005 * Insert: add entry to index
2006 * Update: add entry to index, de|ay remove until commit
2007 * Delete: do nothing, delay remove until commit
2008 * Commit: remove entry delayed from update and delete
2009 * Abort : remove entry added by insert and update
2010 *
2011 * See Notes.txt for the details.
2012 */
2013
2014 int
executeTuxInsertTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)2015 Dbtup::executeTuxInsertTriggers(Signal* signal,
2016 Operationrec* regOperPtr,
2017 Fragrecord* regFragPtr,
2018 Tablerec* regTabPtr)
2019 {
2020 TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
2021 // fill in constant part
2022 req->tableId = regFragPtr->fragTableId;
2023 req->fragId = regFragPtr->fragmentId;
2024 req->pageId = regOperPtr->m_tuple_location.m_page_no;
2025 req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
2026 req->tupVersion = regOperPtr->op_struct.bit_field.tupVersion;
2027 req->opInfo = TuxMaintReq::OpAdd;
2028 return addTuxEntries(signal, regOperPtr, regTabPtr);
2029 }
2030
2031 int
executeTuxUpdateTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)2032 Dbtup::executeTuxUpdateTriggers(Signal* signal,
2033 Operationrec* regOperPtr,
2034 Fragrecord* regFragPtr,
2035 Tablerec* regTabPtr)
2036 {
2037 TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
2038 // fill in constant part
2039 req->tableId = regFragPtr->fragTableId;
2040 req->fragId = regFragPtr->fragmentId;
2041 req->pageId = regOperPtr->m_tuple_location.m_page_no;
2042 req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
2043 req->tupVersion = regOperPtr->op_struct.bit_field.tupVersion;
2044 req->opInfo = TuxMaintReq::OpAdd;
2045 return addTuxEntries(signal, regOperPtr, regTabPtr);
2046 }
2047
2048 int
addTuxEntries(Signal * signal,Operationrec * regOperPtr,Tablerec * regTabPtr)2049 Dbtup::addTuxEntries(Signal* signal,
2050 Operationrec* regOperPtr,
2051 Tablerec* regTabPtr)
2052 {
2053 if (ERROR_INSERTED(4022)) {
2054 jam();
2055 CLEAR_ERROR_INSERT_VALUE;
2056 terrorCode = 9999;
2057 return -1;
2058 }
2059 TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
2060 const DLList<TupTriggerData>& triggerList = regTabPtr->tuxCustomTriggers;
2061 TriggerPtr triggerPtr;
2062 Uint32 failPtrI;
2063 triggerList.first(triggerPtr);
2064 while (triggerPtr.i != RNIL) {
2065 jam();
2066 req->indexId = triggerPtr.p->indexId;
2067 req->errorCode = RNIL;
2068 if (ERROR_INSERTED(4023) &&
2069 ! triggerList.hasNext(triggerPtr)) {
2070 jam();
2071 CLEAR_ERROR_INSERT_VALUE;
2072 terrorCode = 9999;
2073 failPtrI = triggerPtr.i;
2074 goto fail;
2075 }
2076 EXECUTE_DIRECT(DBTUX, GSN_TUX_MAINT_REQ,
2077 signal, TuxMaintReq::SignalLength);
2078 jamEntry();
2079 if (req->errorCode != 0) {
2080 jam();
2081 terrorCode = req->errorCode;
2082 failPtrI = triggerPtr.i;
2083 goto fail;
2084 }
2085 triggerList.next(triggerPtr);
2086 }
2087 return 0;
2088 fail:
2089 req->opInfo = TuxMaintReq::OpRemove;
2090 triggerList.first(triggerPtr);
2091 while (triggerPtr.i != failPtrI) {
2092 jam();
2093 req->indexId = triggerPtr.p->indexId;
2094 req->errorCode = RNIL;
2095 EXECUTE_DIRECT(DBTUX, GSN_TUX_MAINT_REQ,
2096 signal, TuxMaintReq::SignalLength);
2097 jamEntry();
2098 ndbrequire(req->errorCode == 0);
2099 triggerList.next(triggerPtr);
2100 }
2101 #ifdef VM_TRACE
2102 ndbout << "aborted partial tux update: op " << hex << regOperPtr << endl;
2103 #endif
2104 return -1;
2105 }
2106
2107 int
executeTuxDeleteTriggers(Signal * signal,Operationrec * const regOperPtr,Fragrecord * const regFragPtr,Tablerec * const regTabPtr)2108 Dbtup::executeTuxDeleteTriggers(Signal* signal,
2109 Operationrec* const regOperPtr,
2110 Fragrecord* const regFragPtr,
2111 Tablerec* const regTabPtr)
2112 {
2113 // do nothing
2114 return 0;
2115 }
2116
2117 void
executeTuxCommitTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)2118 Dbtup::executeTuxCommitTriggers(Signal* signal,
2119 Operationrec* regOperPtr,
2120 Fragrecord* regFragPtr,
2121 Tablerec* regTabPtr)
2122 {
2123 TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
2124 Uint32 tupVersion;
2125 if (regOperPtr->op_type == ZINSERT) {
2126 if (! regOperPtr->op_struct.bit_field.delete_insert_flag)
2127 return;
2128 jam();
2129 tupVersion= decr_tup_version(regOperPtr->op_struct.bit_field.tupVersion);
2130 } else if (regOperPtr->op_type == ZUPDATE) {
2131 jam();
2132 tupVersion= decr_tup_version(regOperPtr->op_struct.bit_field.tupVersion);
2133 } else if (regOperPtr->op_type == ZDELETE) {
2134 if (regOperPtr->op_struct.bit_field.delete_insert_flag)
2135 return;
2136 jam();
2137 tupVersion= regOperPtr->op_struct.bit_field.tupVersion;
2138 } else if (regOperPtr->op_type == ZREFRESH) {
2139 /* Refresh should not affect TUX */
2140 return;
2141 } else {
2142 ndbrequire(false);
2143 tupVersion= 0; // remove warning
2144 }
2145 // fill in constant part
2146 req->tableId = regFragPtr->fragTableId;
2147 req->fragId = regFragPtr->fragmentId;
2148 req->pageId = regOperPtr->m_tuple_location.m_page_no;
2149 req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
2150 req->tupVersion = tupVersion;
2151 req->opInfo = TuxMaintReq::OpRemove;
2152 removeTuxEntries(signal, regTabPtr);
2153 }
2154
2155 void
executeTuxAbortTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)2156 Dbtup::executeTuxAbortTriggers(Signal* signal,
2157 Operationrec* regOperPtr,
2158 Fragrecord* regFragPtr,
2159 Tablerec* regTabPtr)
2160 {
2161 TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
2162 // get version
2163 Uint32 tupVersion;
2164 if (regOperPtr->op_type == ZINSERT) {
2165 jam();
2166 tupVersion = regOperPtr->op_struct.bit_field.tupVersion;
2167 } else if (regOperPtr->op_type == ZUPDATE) {
2168 jam();
2169 tupVersion = regOperPtr->op_struct.bit_field.tupVersion;
2170 } else if (regOperPtr->op_type == ZDELETE) {
2171 jam();
2172 return;
2173 } else if (regOperPtr->op_type == ZREFRESH) {
2174 jam();
2175 /* Refresh should not affect TUX */
2176 return;
2177 } else {
2178 ndbrequire(false);
2179 tupVersion= 0; // remove warning
2180 }
2181 // fill in constant part
2182 req->tableId = regFragPtr->fragTableId;
2183 req->fragId = regFragPtr->fragmentId;
2184 req->pageId = regOperPtr->m_tuple_location.m_page_no;
2185 req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
2186 req->tupVersion = tupVersion;
2187 req->opInfo = TuxMaintReq::OpRemove;
2188 removeTuxEntries(signal, regTabPtr);
2189 }
2190
2191 void
removeTuxEntries(Signal * signal,Tablerec * regTabPtr)2192 Dbtup::removeTuxEntries(Signal* signal,
2193 Tablerec* regTabPtr)
2194 {
2195 TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
2196 const DLList<TupTriggerData>& triggerList = regTabPtr->tuxCustomTriggers;
2197 TriggerPtr triggerPtr;
2198 triggerList.first(triggerPtr);
2199 while (triggerPtr.i != RNIL) {
2200 jam();
2201 req->indexId = triggerPtr.p->indexId;
2202 req->errorCode = RNIL,
2203 EXECUTE_DIRECT(DBTUX, GSN_TUX_MAINT_REQ,
2204 signal, TuxMaintReq::SignalLength);
2205 jamEntry();
2206 // must succeed
2207 ndbrequire(req->errorCode == 0);
2208 triggerList.next(triggerPtr);
2209 }
2210 }
2211
2212 void
ndbmtd_buffer_suma_trigger(Signal * signal,Uint32 len,LinearSectionPtr sec[3])2213 Dbtup::ndbmtd_buffer_suma_trigger(Signal * signal,
2214 Uint32 len,
2215 LinearSectionPtr sec[3])
2216 {
2217 jam();
2218 Uint32 tot = len + 5;
2219 for (Uint32 i = 0; i<3; i++)
2220 tot += sec[i].sz;
2221
2222 Uint32 * ptr = 0;
2223 Uint32 free = m_suma_trigger_buffer.m_freeWords;
2224 Uint32 pageId = m_suma_trigger_buffer.m_pageId;
2225 Uint32 oom = m_suma_trigger_buffer.m_out_of_memory;
2226 if (free < tot)
2227 {
2228 jam();
2229 if (pageId != RNIL)
2230 {
2231 flush_ndbmtd_suma_buffer(signal);
2232 }
2233 if (oom == 0)
2234 {
2235 jam();
2236 ndbassert(m_suma_trigger_buffer.m_pageId == RNIL);
2237 void * vptr = m_ctx.m_mm.alloc_page(RT_DBTUP_PAGE,
2238 &m_suma_trigger_buffer.m_pageId,
2239 Ndbd_mem_manager::NDB_ZONE_ANY);
2240 ptr = reinterpret_cast<Uint32*>(vptr);
2241 free = GLOBAL_PAGE_SIZE_WORDS - tot;
2242 }
2243 }
2244 else
2245 {
2246 jam();
2247 ptr = reinterpret_cast<Uint32*>(c_page_pool.getPtr(pageId));
2248 ptr += (GLOBAL_PAGE_SIZE_WORDS - free);
2249 free -= tot;
2250 }
2251
2252 if (likely(ptr != 0))
2253 {
2254 jam();
2255 * ptr++ = tot;
2256 * ptr++ = len;
2257 * ptr++ = sec[0].sz;
2258 * ptr++ = sec[1].sz;
2259 * ptr++ = sec[2].sz;
2260 memcpy(ptr, signal->getDataPtrSend(), 4 * len);
2261 ptr += len;
2262 for (Uint32 i = 0; i<3; i++)
2263 {
2264 memcpy(ptr, sec[i].p, 4 * sec[i].sz);
2265 ptr += sec[i].sz;
2266 }
2267
2268 m_suma_trigger_buffer.m_freeWords = free;
2269 if (free < (len + 5))
2270 {
2271 flush_ndbmtd_suma_buffer(signal);
2272 }
2273 }
2274 else
2275 {
2276 jam();
2277 m_suma_trigger_buffer.m_out_of_memory = 1;
2278 }
2279 }
2280
2281 void
flush_ndbmtd_suma_buffer(Signal * signal)2282 Dbtup::flush_ndbmtd_suma_buffer(Signal* signal)
2283 {
2284 jam();
2285
2286 Uint32 pageId = m_suma_trigger_buffer.m_pageId;
2287 Uint32 free = m_suma_trigger_buffer.m_freeWords;
2288 Uint32 oom = m_suma_trigger_buffer.m_out_of_memory;
2289
2290 if (pageId != RNIL)
2291 {
2292 jam();
2293 Uint32 save[2];
2294 save[0] = signal->theData[0];
2295 save[1] = signal->theData[1];
2296 signal->theData[0] = pageId;
2297 signal->theData[1] = GLOBAL_PAGE_SIZE_WORDS - free;
2298 sendSignal(SUMA_REF, GSN_FIRE_TRIG_ORD_L, signal, 2, JBB);
2299
2300 signal->theData[0] = save[0];
2301 signal->theData[1] = save[1];
2302 }
2303 else if (oom)
2304 {
2305 jam();
2306 Uint32 save[2];
2307 save[0] = signal->theData[0];
2308 save[1] = signal->theData[1];
2309 signal->theData[0] = RNIL;
2310 signal->theData[1] = 0;
2311 sendSignal(SUMA_REF, GSN_FIRE_TRIG_ORD_L, signal, 2, JBB);
2312
2313 signal->theData[0] = save[0];
2314 signal->theData[1] = save[1];
2315 }
2316
2317 m_suma_trigger_buffer.m_pageId = RNIL;
2318 m_suma_trigger_buffer.m_freeWords = 0;
2319 m_suma_trigger_buffer.m_out_of_memory = 0;
2320 }
2321
2322 void
execSUB_GCP_COMPLETE_REP(Signal * signal)2323 Dbtup::execSUB_GCP_COMPLETE_REP(Signal* signal)
2324 {
2325 flush_ndbmtd_suma_buffer(signal);
2326 }
2327