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