summaryrefslogtreecommitdiff
path: root/storage/ndb/include/ndbapi/NdbBlob.hpp
blob: 923fc82451d7cc822baf3c8efc8141906abfadf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
/* Copyright (c) 2003-2006 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA */

#ifndef NdbBlob_H
#define NdbBlob_H

#include <ndb_types.h>
#include <NdbDictionary.hpp>
#include <NdbTransaction.hpp>
#include <NdbError.hpp>

class Ndb;
class NdbTransaction;
class NdbOperation;
class NdbRecAttr;
class NdbTableImpl;
class NdbColumnImpl;
class NdbEventOperationImpl;

/**
 * @class NdbBlob
 * @brief Blob handle
 *
 * Blob data is stored in 2 places:
 *
 * - "header" and "inline bytes" stored in the blob attribute
 * - "blob parts" stored in a separate table NDB$BLOB_<tid>_<cid>
 *
 * Inline and part sizes can be set via NdbDictionary::Column methods
 * when the table is created.
 *
 * NdbBlob is a blob handle.  To access blob data, the handle must be
 * created using NdbOperation::getBlobHandle in operation prepare phase.
 * The handle has following states:
 *
 * - prepared: before the operation is executed
 * - active: after execute or next result but before transaction commit
 * - closed: after transaction commit
 * - invalid: after rollback or transaction close
 *
 * NdbBlob supports 3 styles of data access:
 *
 * - in prepare phase, NdbBlob methods getValue and setValue are used to
 *   prepare a read or write of a blob value of known size
 *
 * - in prepare phase, setActiveHook is used to define a routine which
 *   is invoked as soon as the handle becomes active
 *
 * - in active phase, readData and writeData are used to read or write
 *   blob data of arbitrary size
 *
 * The styles can be applied in combination (in above order).
 *
 * Blob operations take effect at next transaction execute.  In some
 * cases NdbBlob is forced to do implicit executes.  To avoid this,
 * operate on complete blob parts.
 *
 * Use NdbTransaction::executePendingBlobOps to flush your reads and
 * writes.  It avoids execute penalty if nothing is pending.  It is not
 * needed after execute (obviously) or after next scan result.
 *
 * NdbBlob also supports reading post or pre blob data from events.  The
 * handle can be read after next event on main table has been retrieved.
 * The data is available immediately.  See NdbEventOperation.
 *
 * Non-void NdbBlob methods return -1 on error and 0 on success.  Output
 * parameters are used when necessary.
 *
 * Usage notes for different operation types:
 *
 * - insertTuple must use setValue if blob attribute is non-nullable
 *
 * - readTuple or scan readTuples with lock mode LM_CommittedRead is
 *   automatically upgraded to lock mode LM_Read if any blob attributes
 *   are accessed (to guarantee consistent view)
 *
 * - readTuple (with any lock mode) can only read blob value
 *
 * - updateTuple can either overwrite existing value with setValue or
 *   update it in active phase
 *
 * - writeTuple always overwrites blob value and must use setValue if
 *   blob attribute is non-nullable
 *
 * - deleteTuple creates implicit non-accessible blob handles
 *
 * - scan readTuples (any lock mode) can use its blob handles only
 *   to read blob value
 *
 * - scan readTuples with lock mode LM_Exclusive can update row and blob
 *   value using updateCurrentTuple, where the operation returned must
 *   create its own blob handles explicitly
 *
 * - scan readTuples with lock mode LM_Exclusive can delete row (and
 *   therefore blob values) using deleteCurrentTuple, which creates
 *   implicit non-accessible blob handles
 *
 * - the operation returned by lockCurrentTuple cannot update blob value
 *
 * Bugs / limitations:
 *
 * - too many pending blob ops can blow up i/o buffers
 *
 * - table and its blob part tables are not created atomically
 */
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
 * - there is no support for an asynchronous interface
 */
#endif

class NdbBlob {
public:
  /**
   * State.
   */
  enum State {
    Idle = 0,
    Prepared = 1,
    Active = 2,
    Closed = 3,
    Invalid = 9
  };
  /**
   * Get the state of a NdbBlob object.
   */
  State getState();
  /**
   * Returns -1 for normal statement based blob and 0/1 for event
   * operation post/pre data blob.  Always succeeds.
   */
  void getVersion(int& version);
  /**
   * Inline blob header.
   */
  struct Head {
    Uint64 length;
  };
  /**
   * Prepare to read blob value.  The value is available after execute.
   * Use getNull() to check for NULL and getLength() to get the real length
   * and to check for truncation.  Sets current read/write position to
   * after the data read.
   */
  int getValue(void* data, Uint32 bytes);
  /**
   * Prepare to insert or update blob value.  An existing longer blob
   * value will be truncated.  The data buffer must remain valid until
   * execute.  Sets current read/write position to after the data.  Set
   * data to null pointer (0) to create a NULL value.
   */
  int setValue(const void* data, Uint32 bytes);
  /**
   * Callback for setActiveHook().  Invoked immediately when the prepared
   * operation has been executed (but not committed).  Any getValue() or
   * setValue() is done first.  The blob handle is active so readData or
   * writeData() etc can be used to manipulate blob value.  A user-defined
   * argument is passed along.  Returns non-zero on error.
   */
  typedef int ActiveHook(NdbBlob* me, void* arg);
  /**
   * Define callback for blob handle activation.  The queue of prepared
   * operations will be executed in no commit mode up to this point and
   * then the callback is invoked.
   */
  int setActiveHook(ActiveHook* activeHook, void* arg);
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
  int getDefined(int& isNull);
  int getNull(bool& isNull);
#endif
  /**
   * Return -1, 0, 1 if blob is undefined, non-null, or null.  For
   * non-event blob, undefined causes a state error.
   */
  int getNull(int& isNull);
  /**
   * Set blob to NULL.
   */
  int setNull();
  /**
   * Get current length in bytes.  Use getNull to distinguish between
   * length 0 blob and NULL blob.
   */
  int getLength(Uint64& length);
  /**
   * Truncate blob to given length.  Has no effect if the length is
   * larger than current length.
   */
  int truncate(Uint64 length = 0);
  /**
   * Get current read/write position.
   */
  int getPos(Uint64& pos);
  /**
   * Set read/write position.  Must be between 0 and current length.
   * "Sparse blobs" are not supported.
   */
  int setPos(Uint64 pos);
  /**
   * Read at current position and set new position to first byte after
   * the data read.  A read past blob end returns actual number of bytes
   * read in the in/out bytes parameter.
   */
  int readData(void* data, Uint32& bytes);
  /**
   * Write at current position and set new position to first byte after
   * the data written.  A write past blob end extends the blob value.
   */
  int writeData(const void* data, Uint32 bytes);
  /**
   * Return the blob column.
   */
  const NdbDictionary::Column* getColumn();
  /**
   * Get blob parts table name.  Useful only to test programs.
   */
  static int getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName);
  /**
   * Get blob event name.  The blob event is created if the main event
   * monitors the blob column.  The name includes main event name.
   */
  static int getBlobEventName(char* bename, Ndb* anNdb, const char* eventName, const char* columnName);
  /**
   * Return error object.  The error may be blob specific or may be
   * copied from a failed implicit operation.
   *
   * The error code is copied back to the operation unless the operation
   * already has a non-zero error code.
   */
  const NdbError& getNdbError() const;
  /**
   * Return info about all blobs in this operation.
   *
   * Get first blob in list.
   */
  NdbBlob* blobsFirstBlob();
  /**
   * Return info about all blobs in this operation.
   *
   * Get next blob in list. Initialize with blobsFirstBlob().
   */
  NdbBlob* blobsNextBlob();

private:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
  friend class Ndb;
  friend class NdbTransaction;
  friend class NdbOperation;
  friend class NdbScanOperation;
  friend class NdbDictionaryImpl;
  friend class NdbResultSet; // atNextResult
  friend class NdbEventBuffer;
  friend class NdbEventOperationImpl;
#endif
  // state
  State theState;
  void setState(State newState);
  // quick and dirty support for events (consider subclassing)
  int theEventBlobVersion; // -1=normal blob 0=post event 1=pre event
  // define blob table
  static void getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c);
  static void getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c);
  static void getBlobEventName(char* bename, const NdbEventImpl* e, const NdbColumnImpl* c);
  static void getBlobEvent(NdbEventImpl& be, const NdbEventImpl* e, const NdbColumnImpl* c);
  // ndb api stuff
  Ndb* theNdb;
  NdbTransaction* theNdbCon;
  NdbOperation* theNdbOp;
  NdbEventOperationImpl* theEventOp;
  NdbEventOperationImpl* theBlobEventOp;
  NdbRecAttr* theBlobEventPkRecAttr;
  NdbRecAttr* theBlobEventDistRecAttr;
  NdbRecAttr* theBlobEventPartRecAttr;
  NdbRecAttr* theBlobEventDataRecAttr;
  const NdbTableImpl* theTable;
  const NdbTableImpl* theAccessTable;
  const NdbTableImpl* theBlobTable;
  const NdbColumnImpl* theColumn;
  char theFillChar;
  // sizes
  Uint32 theInlineSize;
  Uint32 thePartSize;
  Uint32 theStripeSize;
  // getValue/setValue
  bool theGetFlag;
  char* theGetBuf;
  bool theSetFlag;
  const char* theSetBuf;
  Uint32 theGetSetBytes;
  // pending ops
  Uint8 thePendingBlobOps;
  // activation callback
  ActiveHook* theActiveHook;
  void* theActiveHookArg;
  // buffers
  struct Buf {
    char* data;
    unsigned size;
    unsigned maxsize;
    Buf();
    ~Buf();
    void alloc(unsigned n);
    void zerorest();
    void copyfrom(const Buf& src);
  };
  Buf theKeyBuf;
  Buf theAccessKeyBuf;
  Buf thePackKeyBuf;
  Buf theHeadInlineBuf;
  Buf theHeadInlineCopyBuf;     // for writeTuple
  Buf thePartBuf;
  Buf theBlobEventDataBuf;
  Uint32 thePartNumber;         // for event
  Head* theHead;
  char* theInlineData;
  NdbRecAttr* theHeadInlineRecAttr;
  NdbOperation* theHeadInlineReadOp;
  bool theHeadInlineUpdateFlag;
  // length and read/write position
  int theNullFlag;
  Uint64 theLength;
  Uint64 thePos;
  // errors
  NdbError theError;
  // for keeping in lists
  NdbBlob* theNext;
  // initialization
  NdbBlob(Ndb*);
  void init();
  void release();
  // classify operations
  bool isTableOp();
  bool isIndexOp();
  bool isKeyOp();
  bool isReadOp();
  bool isInsertOp();
  bool isUpdateOp();
  bool isWriteOp();
  bool isDeleteOp();
  bool isScanOp();
  bool isReadOnlyOp();
  bool isTakeOverOp();
  // computations
  Uint32 getPartNumber(Uint64 pos);
  Uint32 getPartCount();
  Uint32 getDistKey(Uint32 part);
  // pack / unpack
  int packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf);
  int unpackKeyValue(const NdbTableImpl* aTable, Buf& dstBuf);
  // getters and setters
  int getTableKeyValue(NdbOperation* anOp);
  int setTableKeyValue(NdbOperation* anOp);
  int setAccessKeyValue(NdbOperation* anOp);
  int setPartKeyValue(NdbOperation* anOp, Uint32 part);
  int getHeadInlineValue(NdbOperation* anOp);
  void getHeadFromRecAttr();
  int setHeadInlineValue(NdbOperation* anOp);
  // data operations
  int readDataPrivate(char* buf, Uint32& bytes);
  int writeDataPrivate(const char* buf, Uint32 bytes);
  int readParts(char* buf, Uint32 part, Uint32 count);
  int readTableParts(char* buf, Uint32 part, Uint32 count);
  int readEventParts(char* buf, Uint32 part, Uint32 count);
  int insertParts(const char* buf, Uint32 part, Uint32 count);
  int updateParts(const char* buf, Uint32 part, Uint32 count);
  int deleteParts(Uint32 part, Uint32 count);
  int deletePartsUnknown(Uint32 part);
  // pending ops
  int executePendingBlobReads();
  int executePendingBlobWrites();
  // callbacks
  int invokeActiveHook();
  // blob handle maintenance
  int atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn);
  int atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, const NdbColumnImpl* aColumn, int version);
  int prepareColumn();
  int preExecute(NdbTransaction::ExecType anExecType, bool& batch);
  int postExecute(NdbTransaction::ExecType anExecType);
  int preCommit();
  int atNextResult();
  int atNextEvent();
  // errors
  void setErrorCode(int anErrorCode, bool invalidFlag = false);
  void setErrorCode(NdbOperation* anOp, bool invalidFlag = false);
  void setErrorCode(NdbTransaction* aCon, bool invalidFlag = false);
  void setErrorCode(NdbEventOperationImpl* anOp, bool invalidFlag = false);
#ifdef VM_TRACE
  int getOperationType() const;
  friend class NdbOut& operator<<(NdbOut&, const NdbBlob&);
#endif
  // list stuff
  void next(NdbBlob* obj) { theNext= obj;}
  NdbBlob* next() { return theNext;}
  friend struct Ndb_free_list_t<NdbBlob>;
};

#endif