/* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef NDBMEMCACHE_OPERATION_H #define NDBMEMCACHE_OPERATION_H #ifndef __cplusplus #error "This file is for C++ only" #endif #include #include "ndbmemcache_global.h" #include "Record.h" #include "QueryPlan.h" #include "debug.h" #include "workitem.h" /* Use a QueryPlan to perform an operation. A query plan owns three records: a key_record, a val_record, and a row_record. In general, the purpose of the Operation class is to hide this fact from the user, and to perform one of Record's method using the correct record. */ class Operation { public: /* Pointers to buffers used in operations. These are public because the caller owns the memory they point to. */ char *buffer; char *key_buffer; private: /* Private instance variables */ const QueryPlan *plan; const int op; const Record *record; Uint8 row_mask[4]; Uint8 key_mask[4]; Uint8 * read_mask_ptr; /* Private methods */ void set_default_record(); bool setFieldsInRow(int offset, const char *type, int, const char *, size_t); public: // Constructors Operation(QueryPlan *p, int o = 1, char *kbuf = 0); Operation(workitem *, Uint32 saved_row_mask = 0); Operation(QueryPlan *p, char * buffer); // Public Methods void save_row_mask(Uint32 * loc); // Select columns for reading void readSelectedColumns(); void readAllColumns(); void readColumn(int id); // Methods for writing to the key record size_t requiredKeyBuffer(); void clearKeyNullBits(); bool setKey(int nparts, const char *key_str, size_t key_str_len); bool setKeyPart(int id, const char *strval, size_t strlen); bool setKeyPartInt(int id, int value); void setKeyPartNull(int id); // Methods for writing to the row size_t requiredBuffer(); void setNullBits(); void clearNullBits(); bool setKeyFieldsInRow(int nparts, const char *key_str, size_t key_str_len); bool setValueFieldsInRow(int nparts, const char *val_str, size_t val_str_len); bool setColumn(int id, const char *strval, size_t strlen); bool setColumnInt(int id, int value); bool setColumnBigUnsigned(int id, Uint64 value); void setColumnNull(int id); void setColumnNotNull(int id); // Methods for reading columns from the response int nValues() const; bool isNull(int id) const; size_t getStringifiedLength() const; void * getPointer(int id) const; int getIntValue(int id) const; Uint64 getBigUnsignedValue(int id) const; bool getStringValueNoCopy(int id, char **dstptr, size_t *lenptr) const; bool appendCRLF(int id, size_t len) const; size_t copyValue(int id, char *dest) const; /* NdbTransaction method wrappers */ // startTransaction NdbTransaction *startTransaction(Ndb *) const; // read const NdbOperation *readTuple(NdbTransaction *tx, NdbOperation::LockMode lmod = NdbOperation::LM_SimpleRead); // delete const NdbOperation *deleteTuple(NdbTransaction *tx, NdbOperation::OperationOptions *options = 0); const NdbOperation *deleteCurrentTuple(NdbScanOperation *, NdbTransaction *, NdbOperation::OperationOptions *opts = 0); // write const NdbOperation *writeTuple(NdbTransaction *tx); const NdbOperation *insertRow(NdbTransaction *tx); const NdbOperation *insertTuple(NdbTransaction *tx, NdbOperation::OperationOptions *options = 0); const NdbOperation *updateTuple(NdbTransaction *tx, NdbOperation::OperationOptions *options = 0); // scan NdbScanOperation *scanTable(NdbTransaction *tx, NdbOperation::LockMode lmod = NdbOperation::LM_Read, NdbScanOperation::ScanOptions *options = 0); NdbIndexScanOperation *scanIndex(NdbTransaction *tx, NdbIndexScanOperation::IndexBound *bound); }; /* ================= Inline methods ================= */ inline void Operation::save_row_mask(Uint32 * loc) { memcpy(loc, row_mask, 4); } /* Select columns for reading */ inline void Operation::readSelectedColumns() { read_mask_ptr = row_mask; } inline void Operation::readAllColumns() { read_mask_ptr = 0; } inline void Operation::readColumn(int id) { record->maskActive(id, row_mask); } /* Methods for writing to the key record */ inline size_t Operation::requiredKeyBuffer() { /* Malloc checkers complain if this +1 is not present. Not sure why. Theory: because the terminating null of a C-string may be written there. */ return plan->key_record->rec_size + 1; } inline void Operation::clearKeyNullBits() { plan->key_record->clearNullBits(key_buffer); } inline bool Operation::setKeyPart(int id, const char *strval, size_t str_len) { int s = plan->key_record->encode(id, strval, str_len, key_buffer, key_mask); return (s > 0); } inline bool Operation::setKeyPartInt(int id, int value) { return plan->key_record->setIntValue(id, value, key_buffer, key_mask); } inline void Operation::setKeyPartNull(int id) { plan->key_record->setNull(id, key_buffer, key_mask); } /* Methods for writing to the row */ inline size_t Operation::requiredBuffer() { return record->rec_size + 1; } inline void Operation::setNullBits() { record->setNullBits(buffer); } inline void Operation::clearNullBits() { record->clearNullBits(buffer); } inline bool Operation::setColumn(int id, const char *strval, size_t strlen) { int s = record->encode(id, strval, strlen, buffer, row_mask); return (s > 0); } inline bool Operation::setColumnInt(int id, int value) { return record->setIntValue(id, value, buffer, row_mask); } inline bool Operation::setColumnBigUnsigned(int id, Uint64 value) { return record->setUint64Value(id, value, buffer, row_mask); } inline void Operation::setColumnNull(int id) { record->setNull(id, buffer, row_mask); } inline void Operation::setColumnNotNull(int id) { record->setNotNull(id, buffer, row_mask); } inline bool Operation::setKeyFieldsInRow(int nparts, const char *dbkey, size_t key_len) { return setFieldsInRow(COL_STORE_KEY, "key", nparts, dbkey, key_len); } inline bool Operation::setValueFieldsInRow(int nparts, const char *dbval, size_t val_len) { return setFieldsInRow(COL_STORE_VALUE, "value", nparts, dbval, val_len); } /* Methods for reading columns from the response */ inline int Operation::nValues() const { return record->nvalues; } inline bool Operation::isNull(int id) const { return record->isNull(id, buffer); } inline size_t Operation::getStringifiedLength() const { return record->getStringifiedLength(buffer); } inline void * Operation::getPointer(int id) const { return record->getPointer(id, buffer); } inline int Operation::getIntValue(int id) const { return record->getIntValue(id, buffer); } inline Uint64 Operation::getBigUnsignedValue(int id) const { return record->getUint64Value(id, buffer); } inline bool Operation::appendCRLF(int id, size_t len) const { return record->appendCRLF(id, len, buffer); } /* NdbTransaction method wrappers */ inline const NdbOperation * Operation::readTuple(NdbTransaction *tx, NdbOperation::LockMode lmode) { return tx->readTuple(plan->key_record->ndb_record, key_buffer, record->ndb_record, buffer, lmode, read_mask_ptr); } inline const NdbOperation * Operation::deleteTuple(NdbTransaction *tx, NdbOperation::OperationOptions * options) { return tx->deleteTuple(plan->key_record->ndb_record, key_buffer, plan->val_record->ndb_record, 0, 0, options); } inline const NdbOperation * Operation::writeTuple(NdbTransaction *tx) { return tx->writeTuple(plan->key_record->ndb_record, key_buffer, plan->row_record->ndb_record, buffer, row_mask); } inline const NdbOperation * Operation::insertRow(NdbTransaction *tx) { return tx->insertTuple(plan->row_record->ndb_record, buffer, row_mask); } inline const NdbOperation * Operation::insertTuple(NdbTransaction *tx, NdbOperation::OperationOptions * options) { return tx->insertTuple(plan->key_record->ndb_record, key_buffer, plan->row_record->ndb_record, buffer, row_mask, options); } inline const NdbOperation * Operation::updateTuple(NdbTransaction *tx, NdbOperation::OperationOptions * options) { return tx->updateTuple(plan->key_record->ndb_record, key_buffer, plan->row_record->ndb_record, buffer, row_mask, options); } inline NdbScanOperation * Operation::scanTable(NdbTransaction *tx, NdbOperation::LockMode lmode, NdbScanOperation::ScanOptions *opts) { return tx->scanTable(record->ndb_record, lmode, read_mask_ptr, opts, 0); } inline const NdbOperation * Operation::deleteCurrentTuple(NdbScanOperation *scanop, NdbTransaction *tx, NdbOperation::OperationOptions *opts) { return scanop->deleteCurrentTuple(tx, record->ndb_record, buffer, read_mask_ptr, opts); } #endif