/*
   Copyright (c) 2016, 2021, 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, version 2.0,
   as published by the Free Software Foundation.

   This program is also distributed with certain software (including
   but not limited to OpenSSL) that is licensed under separate terms,
   as designated in a particular file or component or in included license
   documentation.  The authors of MySQL hereby grant you an additional
   permission to link the program and your derivative works with the
   separately licensed software that they have included with MySQL.

   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, version 2.0, 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 NDB_TABLE_MAP_H
#define NDB_TABLE_MAP_H

#include <my_global.h>
#include <my_bitmap.h>

/** Ndb_table_map
*
*   An Ndb_table_map for a table provides a map between MySQL fields and
*   NDB columns.  Some MySQL fields, such as virtual generated columns, do
*   not exist in NDB.  Some NDB columns, such as hidden primary keys and
*   partition ID columns, are not visible as MySQL fields.
*
*   Ndb_table_map provides a getColumn() method that wraps
*   NdbDictionary::Table::getColumn(), translating from a field number to the
*   appropriate column number.  It also provides a method get_column_mask()
*   for wholesale translation, when needed, of an entire bitmap of field
*   numbers to column numbers.
*
*   The introduction of virtual generated columns from WL#411 requires the
*   handler to understand that some fields are not stored, and to map between 
*   MySQL Field Ids and NDB Column Ids (which are no longer equivalent).
*
*/
class Ndb_table_map {
public:
  Ndb_table_map(struct TABLE*, const NdbDictionary::Table * ndb_table = 0);
  ~Ndb_table_map();

  /* Get the NDB column number for a MySQL field.
     The user must check field->stored_in_db, and only look up stored fields.
  */
  uint get_column_for_field(uint mysql_field_number) const;

  /* Get an NDB column by MySQL field number.
     The user must check field->stored_in_db, and only look up stored fields.
  */
  const NdbDictionary::Column * getColumn(uint mysql_field_number) const;

  /* Get column by field number; non-const version for CREATE TABLE.
     The user must check field->stored_in_db, and only look up stored fields.
  */
  NdbDictionary::Column * getColumn(NdbDictionary::Table &,
                                    uint mysql_field_number) const;

  /* Get Blob handle by MySQL field number.
     The user must check field->stored_in_db, and only look up stored fields.
  */
  NdbBlob * getBlobHandle(const NdbOperation *, uint mysql_field_number) const;

  /* Get NDB column numbers for special columns that are hidden from MySQL */
  uint get_hidden_key_column() const;
  uint get_partition_id_column() const;

  /* Get the MySQL field number for an NBD column */
  uint get_field_for_column(uint ndb_col_number) const;

  /* get_column_mask():
     Takes a pointer to a MySQL bitmask.  
     Returns a pointer which can be used as a record mask when building an
     NdbRecord operation.

     If mysql_field_map is NULL, rewrite_bitmap() returns NULL.

     If mysql_field_map is non-NULL but translation is not necessary,
     rewrite_bitmap() returns a pointer to the bitmap within mysql_field_map.

     If necessary, rewrite_bitmap() will update an internal bitmask to provide
     a translation from the field numbers in mysql_field_map to NDB column
     numbers, and return a pointer to the bitmap in this mask.  The memory
     for this internal bitmask is owned by Ndb_table_map and will be reused
     by subsequent calls to rewrite_bitmap().
 */
  unsigned char * get_column_mask(const MY_BITMAP * mysql_field_map);

private:
  const NdbDictionary::Table * m_ndb_table;
  MY_BITMAP m_moved_fields;
  MY_BITMAP m_rewrite_set;
  int * m_map_by_field;
  int * m_map_by_col;
  const uint m_array_size;
  const uint m_stored_fields;
  const unsigned short m_hidden_pk;
  const bool m_trivial;
};


// inline implementations

inline const NdbDictionary::Column * Ndb_table_map::getColumn(uint field) const
{
  return m_ndb_table->getColumn(get_column_for_field(field));
}

inline NdbDictionary::Column *
  Ndb_table_map::getColumn(NdbDictionary::Table & create_table, uint field) const
{
  return create_table.getColumn(get_column_for_field(field));
}

inline NdbBlob * Ndb_table_map::getBlobHandle(const NdbOperation *ndb_op,
                                              uint mysql_field_number) const
{
  return ndb_op->getBlobHandle(get_column_for_field(mysql_field_number));
}

inline uint Ndb_table_map::get_hidden_key_column() const
{
  assert(m_hidden_pk);
  // The hidden primary key is just after the final stored, visible column
  return m_stored_fields;
}

inline uint Ndb_table_map::get_partition_id_column() const
{
  // The hidden partition id, if present, is the final column
  return m_stored_fields + m_hidden_pk;
}



#endif
