NdbBlob.hpp 10.3 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* Copyright (C) 2003 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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef NdbBlob_H
#define NdbBlob_H

#include <ndb_types.h>
#include <NdbDictionary.hpp>
22
#include <NdbTransaction.hpp>
unknown's avatar
unknown committed
23 24 25
#include <NdbError.hpp>

class Ndb;
26
class NdbTransaction;
unknown's avatar
unknown committed
27 28 29 30 31 32 33 34 35 36 37 38
class NdbOperation;
class NdbRecAttr;
class NdbTableImpl;
class NdbColumnImpl;

/**
 * @class NdbBlob
 * @brief Blob handle
 *
 * Blob data is stored in 2 places:
 *
 * - "header" and "inline bytes" stored in the blob attribute
39
 * - "blob parts" stored in a separate table NDB$BLOB_<tid>_<cid>
unknown's avatar
unknown committed
40 41 42 43 44 45 46 47 48 49 50 51 52
 *
 * 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
 *
unknown's avatar
unknown committed
53
 * NdbBlob supports 3 styles of data access:
unknown's avatar
unknown committed
54 55
 *
 * - in prepare phase, NdbBlob methods getValue and setValue are used to
unknown's avatar
unknown committed
56
 *   prepare a read or write of a blob value of known size
unknown's avatar
unknown committed
57
 *
unknown's avatar
unknown committed
58 59 60 61 62 63 64 65 66 67 68 69
 * - 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.
 *
70
 * Use NdbTransaction::executePendingBlobOps to flush your reads and
unknown's avatar
unknown committed
71 72
 * writes.  It avoids execute penalty if nothing is pending.  It is not
 * needed after execute (obviously) or after next scan result.
unknown's avatar
unknown committed
73 74 75 76
 *
 * NdbBlob methods return -1 on error and 0 on success, and use output
 * parameters when necessary.
 *
77 78 79 80 81 82 83 84
 * Operation types:
 * - insertTuple must use setValue if blob column is non-nullable
 * - readTuple with exclusive lock can also update existing value
 * - updateTuple can overwrite with setValue or update existing value
 * - writeTuple always overwrites and must use setValue if non-nullable
 * - deleteTuple creates implicit non-accessible blob handles
 * - scan with exclusive lock can also update existing value
 * - scan "lock takeover" update op must do its own getBlobHandle
unknown's avatar
unknown committed
85 86
 *
 * Bugs / limitations:
87 88 89 90
 * - lock mode upgrade should be handled automatically
 * - lock mode vs allowed operation is not checked
 * - too many pending blob ops can blow up i/o buffers
 * - table and its blob part tables are not created atomically
91
 */
92
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
93
/**
94
 * - there is no support for an asynchronous interface
unknown's avatar
unknown committed
95
 */
96 97
#endif

unknown's avatar
unknown committed
98 99
class NdbBlob {
public:
unknown's avatar
unknown committed
100 101 102
  /**
   * State.
   */
unknown's avatar
unknown committed
103 104 105 106 107 108 109
  enum State {
    Idle = 0,
    Prepared = 1,
    Active = 2,
    Closed = 3,
    Invalid = 9
  };
unknown's avatar
unknown committed
110 111 112
  /**
   * Get the state of a NdbBlob object.
   */
unknown's avatar
unknown committed
113
  State getState();
unknown's avatar
unknown committed
114 115 116 117 118 119
  /**
   * Inline blob header.
   */
  struct Head {
    Uint64 length;
  };
unknown's avatar
unknown committed
120 121
  /**
   * Prepare to read blob value.  The value is available after execute.
unknown's avatar
unknown committed
122
   * Use getNull() to check for NULL and getLength() to get the real length
unknown's avatar
unknown committed
123 124 125 126 127 128 129 130 131 132 133
   * 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);
unknown's avatar
unknown committed
134
  /**
unknown's avatar
unknown committed
135 136 137 138
   * 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
unknown's avatar
unknown committed
139 140 141 142 143 144 145 146 147
   * 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);
unknown's avatar
unknown committed
148 149 150 151 152 153 154 155 156
  /**
   * Check if blob is null.
   */
  int getNull(bool& isNull);
  /**
   * Set blob to NULL.
   */
  int setNull();
  /**
unknown's avatar
unknown committed
157
   * Get current length in bytes.  Use getNull to distinguish between
unknown's avatar
unknown committed
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
   * 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);
  /**
   * Return error object.  The error may be blob specific (below) or may
   * be copied from a failed implicit operation.
   */
  const NdbError& getNdbError() const;
unknown's avatar
unknown committed
199 200
  /**
   * Return info about all blobs in this operation.
unknown's avatar
unknown committed
201 202
   *
   * Get first blob in list.
unknown's avatar
unknown committed
203 204
   */
  NdbBlob* blobsFirstBlob();
unknown's avatar
unknown committed
205 206 207 208 209
  /**
   * Return info about all blobs in this operation.
   *
   * Get next blob in list. Initialize with blobsFirstBlob().
   */
unknown's avatar
unknown committed
210
  NdbBlob* blobsNextBlob();
unknown's avatar
unknown committed
211 212

private:
213
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
unknown's avatar
unknown committed
214
  friend class Ndb;
215
  friend class NdbTransaction;
unknown's avatar
unknown committed
216 217 218
  friend class NdbOperation;
  friend class NdbScanOperation;
  friend class NdbDictionaryImpl;
unknown's avatar
unknown committed
219
  friend class NdbResultSet; // atNextResult
220
#endif
unknown's avatar
unknown committed
221 222 223 224 225 226 227 228
  // state
  State theState;
  void setState(State newState);
  // 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);
  // ndb api stuff
  Ndb* theNdb;
229
  NdbTransaction* theNdbCon;
unknown's avatar
unknown committed
230
  NdbOperation* theNdbOp;
unknown's avatar
unknown committed
231 232 233
  const NdbTableImpl* theTable;
  const NdbTableImpl* theAccessTable;
  const NdbTableImpl* theBlobTable;
unknown's avatar
unknown committed
234 235 236 237 238 239 240 241 242 243 244 245
  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;
unknown's avatar
unknown committed
246 247 248 249 250
  // pending ops
  Uint8 thePendingBlobOps;
  // activation callback
  ActiveHook* theActiveHook;
  void* theActiveHookArg;
unknown's avatar
unknown committed
251 252 253 254 255 256 257 258
  // buffers
  struct Buf {
    char* data;
    unsigned size;
    unsigned maxsize;
    Buf();
    ~Buf();
    void alloc(unsigned n);
259
    void copyfrom(const Buf& src);
unknown's avatar
unknown committed
260 261 262 263
  };
  Buf theKeyBuf;
  Buf theAccessKeyBuf;
  Buf theHeadInlineBuf;
264
  Buf theHeadInlineCopyBuf;     // for writeTuple
unknown's avatar
unknown committed
265 266 267 268
  Buf thePartBuf;
  Head* theHead;
  char* theInlineData;
  NdbRecAttr* theHeadInlineRecAttr;
269
  NdbOperation* theHeadInlineReadOp;
unknown's avatar
unknown committed
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
  bool theHeadInlineUpdateFlag;
  // length and read/write position
  int theNullFlag;
  Uint64 theLength;
  Uint64 thePos;
  // errors
  NdbError theError;
  // for keeping in lists
  NdbBlob* theNext;
  // initialization
  NdbBlob();
  void init();
  void release();
  // classify operations
  bool isTableOp();
  bool isIndexOp();
  bool isKeyOp();
  bool isReadOp();
  bool isInsertOp();
  bool isUpdateOp();
290
  bool isWriteOp();
unknown's avatar
unknown committed
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
  bool isDeleteOp();
  bool isScanOp();
  // computations
  Uint32 getPartNumber(Uint64 pos);
  Uint32 getPartCount();
  Uint32 getDistKey(Uint32 part);
  // 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
306 307
  int readDataPrivate(char* buf, Uint32& bytes);
  int writeDataPrivate(const char* buf, Uint32 bytes);
unknown's avatar
unknown committed
308 309 310 311
  int readParts(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);
312
  int deletePartsUnknown(Uint32 part);
unknown's avatar
unknown committed
313 314 315 316 317
  // pending ops
  int executePendingBlobReads();
  int executePendingBlobWrites();
  // callbacks
  int invokeActiveHook();
unknown's avatar
unknown committed
318
  // blob handle maintenance
319
  int atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn);
320 321
  int preExecute(NdbTransaction::ExecType anExecType, bool& batch);
  int postExecute(NdbTransaction::ExecType anExecType);
unknown's avatar
unknown committed
322 323 324 325 326
  int preCommit();
  int atNextResult();
  // errors
  void setErrorCode(int anErrorCode, bool invalidFlag = true);
  void setErrorCode(NdbOperation* anOp, bool invalidFlag = true);
327
  void setErrorCode(NdbTransaction* aCon, bool invalidFlag = true);
unknown's avatar
unknown committed
328
#ifdef VM_TRACE
unknown's avatar
unknown committed
329
  int getOperationType() const;
unknown's avatar
unknown committed
330 331 332 333 334
  friend class NdbOut& operator<<(NdbOut&, const NdbBlob&);
#endif
};

#endif