1 /// \file DS_Table.h 2 /// 3 /// This file is part of RakNet Copyright 2003 Jenkins Software LLC 4 /// 5 /// Raknet is available under the terms of the GPLv3 license, see /usr/local/share/licenses/raknet-3.9.2_10,1/GPLv3. 6 7 #ifndef __TABLE_H 8 #define __TABLE_H 9 10 #ifdef _MSC_VER 11 #pragma warning( push ) 12 #endif 13 14 #include "DS_List.h" 15 #include "DS_BPlusTree.h" 16 #include "RakMemoryOverride.h" 17 #include "Export.h" 18 #include "RakString.h" 19 20 #define _TABLE_BPLUS_TREE_ORDER 16 21 #define _TABLE_MAX_COLUMN_NAME_LENGTH 64 22 23 /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures 24 /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. 25 namespace DataStructures 26 { 27 28 /// \brief Holds a set of columns, a set of rows, and rows times columns cells. 29 /// \details The table data structure is useful if you want to store a set of structures and perform queries on those structures.<BR> 30 /// This is a relatively simple and fast implementation of the types of tables commonly used in databases.<BR> 31 /// See TableSerializer to serialize data members of the table.<BR> 32 /// See LightweightDatabaseClient and LightweightDatabaseServer to transmit the table over the network. 33 class RAK_DLL_EXPORT Table 34 { 35 public: 36 37 enum ColumnType 38 { 39 // Cell::i used 40 NUMERIC, 41 42 // Cell::c used to hold a null terminated string. 43 STRING, 44 45 // Cell::c holds data. Cell::i holds data length of c in bytes. 46 BINARY, 47 48 // Cell::c holds data. Not deallocated. Set manually by assigning ptr. 49 POINTER, 50 }; 51 52 53 /// Holds the actual data in the table 54 // Note: If this structure is changed the struct in the swig files need to be changed as well 55 struct RAK_DLL_EXPORT Cell 56 { 57 Cell(); 58 ~Cell(); 59 Cell(double numericValue, char *charValue, void *ptr, ColumnType type); 60 void SetByType(double numericValue, char *charValue, void *ptr, ColumnType type); 61 void Clear(void); 62 63 /// Numeric 64 void Set(int input); 65 void Set(unsigned int input); 66 void Set(double input); 67 68 /// String 69 void Set(const char *input); 70 71 /// Binary 72 void Set(const char *input, int inputLength); 73 74 /// Pointer 75 void SetPtr(void* p); 76 77 /// Numeric 78 void Get(int *output); 79 void Get(double *output); 80 81 /// String 82 void Get(char *output); 83 84 /// Binary 85 void Get(char *output, int *outputLength); 86 87 RakNet::RakString ToString(ColumnType columnType); 88 89 // assignment operator and copy constructor 90 Cell& operator = ( const Cell& input ); 91 Cell( const Cell & input); 92 93 ColumnType EstimateColumnType(void) const; 94 95 bool isEmpty; 96 double i; 97 char *c; 98 void *ptr; 99 }; 100 101 /// Stores the name and type of the column 102 /// \internal 103 // Note: If this structure is changed the struct in the swig files need to be changed as well 104 struct RAK_DLL_EXPORT ColumnDescriptor 105 { 106 ColumnDescriptor(); 107 ~ColumnDescriptor(); 108 ColumnDescriptor(const char cn[_TABLE_MAX_COLUMN_NAME_LENGTH],ColumnType ct); 109 110 char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]; 111 ColumnType columnType; 112 }; 113 114 /// Stores the list of cells for this row, and a special flag used for internal sorting 115 // Note: If this structure is changed the struct in the swig files need to be changed as well 116 struct RAK_DLL_EXPORT Row 117 { 118 // list of cells 119 DataStructures::List<Cell*> cells; 120 121 /// Numeric 122 void UpdateCell(unsigned columnIndex, double value); 123 124 /// String 125 void UpdateCell(unsigned columnIndex, const char *str); 126 127 /// Binary 128 void UpdateCell(unsigned columnIndex, int byteLength, const char *data); 129 }; 130 131 // Operations to perform for cell comparison 132 enum FilterQueryType 133 { 134 QF_EQUAL, 135 QF_NOT_EQUAL, 136 QF_GREATER_THAN, 137 QF_GREATER_THAN_EQ, 138 QF_LESS_THAN, 139 QF_LESS_THAN_EQ, 140 QF_IS_EMPTY, 141 QF_NOT_EMPTY, 142 }; 143 144 // Compare the cell value for a row at columnName to the cellValue using operation. 145 // Note: If this structure is changed the struct in the swig files need to be changed as well 146 struct RAK_DLL_EXPORT FilterQuery 147 { 148 FilterQuery(); 149 ~FilterQuery(); 150 FilterQuery(unsigned column, Cell *cell, FilterQueryType op); 151 152 // If columnName is specified, columnIndex will be looked up using it. 153 char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]; 154 unsigned columnIndex; 155 Cell *cellValue; 156 FilterQueryType operation; 157 }; 158 159 /// Increasing or decreasing sort order 160 enum SortQueryType 161 { 162 QS_INCREASING_ORDER, 163 QS_DECREASING_ORDER, 164 }; 165 166 // Sort on increasing or decreasing order for a particular column 167 // Note: If this structure is changed the struct in the swig files need to be changed as well 168 struct RAK_DLL_EXPORT SortQuery 169 { 170 /// The index of the table column we are sorting on 171 unsigned columnIndex; 172 173 /// See SortQueryType 174 SortQueryType operation; 175 }; 176 177 // Constructor 178 Table(); 179 180 // Destructor 181 ~Table(); 182 183 /// \brief Adds a column to the table 184 /// \param[in] columnName The name of the column 185 /// \param[in] columnType What type of data this column will hold 186 /// \return The index of the new column 187 unsigned AddColumn(const char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH], ColumnType columnType); 188 189 /// \brief Removes a column by index 190 /// \param[in] columnIndex The index of the column to remove 191 void RemoveColumn(unsigned columnIndex); 192 193 /// \brief Gets the index of a column by name 194 /// \details Column indices are stored in the order they are added. 195 /// \param[in] columnName The name of the column 196 /// \return The index of the column, or (unsigned)-1 if no such column 197 unsigned ColumnIndex(char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]) const; 198 unsigned ColumnIndex(const char *columnName) const; 199 200 /// \brief Gives the string name of the column at a certain index 201 /// \param[in] index The index of the column 202 /// \return The name of the column, or 0 if an invalid index 203 char* ColumnName(unsigned index) const; 204 205 /// \brief Returns the type of a column, referenced by index 206 /// \param[in] index The index of the column 207 /// \return The type of the column 208 ColumnType GetColumnType(unsigned index) const; 209 210 /// Returns the number of columns 211 /// \return The number of columns in the table 212 unsigned GetColumnCount(void) const; 213 214 /// Returns the number of rows 215 /// \return The number of rows in the table 216 unsigned GetRowCount(void) const; 217 218 /// \brief Adds a row to the table 219 /// \details New rows are added with empty values for all cells. However, if you specify initialCelLValues you can specify initial values 220 /// It's up to you to ensure that the values in the specific cells match the type of data used by that row 221 /// rowId can be considered the primary key for the row. It is much faster to lookup a row by its rowId than by searching keys. 222 /// rowId must be unique 223 /// Rows are stored in sorted order in the table, using rowId as the sort key 224 /// \param[in] rowId The UNIQUE primary key for the row. This can never be changed. 225 /// \param[in] initialCellValues Initial values to give the row (optional) 226 /// \return The newly added row 227 Table::Row* AddRow(unsigned rowId); 228 Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell> &initialCellValues); 229 Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell*> &initialCellValues, bool copyCells=false); 230 231 /// \brief Removes a row specified by rowId. 232 /// \param[in] rowId The ID of the row 233 /// \return true if the row was deleted. False if not. 234 bool RemoveRow(unsigned rowId); 235 236 /// \brief Removes all the rows with IDs that the specified table also has. 237 /// \param[in] tableContainingRowIDs The IDs of the rows 238 void RemoveRows(Table *tableContainingRowIDs); 239 240 /// \brief Updates a particular cell in the table. 241 /// \note If you are going to update many cells of a particular row, it is more efficient to call GetRow and perform the operations on the row directly. 242 /// \note Row pointers do not change, so you can also write directly to the rows for more efficiency. 243 /// \param[in] rowId The ID of the row 244 /// \param[in] columnIndex The column of the cell 245 /// \param[in] value The data to set 246 bool UpdateCell(unsigned rowId, unsigned columnIndex, int value); 247 bool UpdateCell(unsigned rowId, unsigned columnIndex, char *str); 248 bool UpdateCell(unsigned rowId, unsigned columnIndex, int byteLength, char *data); 249 bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int value); 250 bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, char *str); 251 bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int byteLength, char *data); 252 253 /// \brief Note this is much less efficient to call than GetRow, then working with the cells directly. 254 /// Numeric, string, binary 255 void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, int *output); 256 void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output); 257 void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output, int *outputLength); 258 259 /// \brief Gets a row. More efficient to do this and access Row::cells than to repeatedly call GetCell. 260 /// You can also update cells in rows from this function. 261 /// \param[in] rowId The ID of the row 262 /// \return The desired row, or 0 if no such row. 263 Row* GetRowByID(unsigned rowId) const; 264 265 /// \brief Gets a row at a specific index. 266 /// rowIndex should be less than GetRowCount() 267 /// \param[in] rowIndex The index of the row 268 /// \param[out] key The ID of the row returned 269 /// \return The desired row, or 0 if no such row. 270 Row* GetRowByIndex(unsigned rowIndex, unsigned *key) const; 271 272 /// \brief Queries the table, optionally returning only a subset of columns and rows. 273 /// \param[in] columnSubset An array of column indices. Only columns in this array are returned. Pass 0 for all columns 274 /// \param[in] numColumnSubset The number of elements in \a columnSubset 275 /// \param[in] inclusionFilters An array of FilterQuery. All filters must pass for the row to be returned. 276 /// \param[in] numInclusionFilters The number of elements in \a inclusionFilters 277 /// \param[in] rowIds An arrow of row IDs. Only these rows with these IDs are returned. Pass 0 for all rows. 278 /// \param[in] numRowIDs The number of elements in \a rowIds 279 /// \param[out] result The result of the query. If no rows are returned, the table will only have columns. 280 void QueryTable(unsigned *columnIndicesSubset, unsigned numColumnSubset, FilterQuery *inclusionFilters, unsigned numInclusionFilters, unsigned *rowIds, unsigned numRowIDs, Table *result); 281 282 /// \brief Sorts the table by rows 283 /// \details You can sort the table in ascending or descending order on one or more columns 284 /// Columns have precedence in the order they appear in the \a sortQueries array 285 /// If a row cell on column n has the same value as a a different row on column n, then the row will be compared on column n+1 286 /// \param[in] sortQueries A list of SortQuery structures, defining the sorts to perform on the table 287 /// \param[in] numColumnSubset The number of elements in \a numSortQueries 288 /// \param[out] out The address of an array of Rows, which will receive the sorted output. The array must be long enough to contain all returned rows, up to GetRowCount() 289 void SortTable(Table::SortQuery *sortQueries, unsigned numSortQueries, Table::Row** out); 290 291 /// \brief Frees all memory in the table. 292 void Clear(void); 293 294 /// \brief Prints out the names of all the columns. 295 /// \param[out] out A pointer to an array of bytes which will hold the output. 296 /// \param[in] outLength The size of the \a out array 297 /// \param[in] columnDelineator What character to print to delineate columns 298 void PrintColumnHeaders(char *out, int outLength, char columnDelineator) const; 299 300 /// \brief Writes a text representation of the row to \a out. 301 /// \param[out] out A pointer to an array of bytes which will hold the output. 302 /// \param[in] outLength The size of the \a out array 303 /// \param[in] columnDelineator What character to print to delineate columns 304 /// \param[in] printDelineatorForBinary Binary output is not printed. True to still print the delineator. 305 /// \param[in] inputRow The row to print 306 void PrintRow(char *out, int outLength, char columnDelineator, bool printDelineatorForBinary, Table::Row* inputRow) const; 307 308 /// \brief Direct access to make things easier. 309 const DataStructures::List<ColumnDescriptor>& GetColumns(void) const; 310 311 /// \brief Direct access to make things easier. 312 const DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER>& GetRows(void) const; 313 314 /// \brief Get the head of a linked list containing all the row data. 315 DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> * GetListHead(void); 316 317 /// \brief Get the first free row id. 318 /// This could be made more efficient. 319 unsigned GetAvailableRowId(void) const; 320 321 Table& operator = ( const Table& input ); 322 323 protected: 324 Table::Row* AddRowColumns(unsigned rowId, Row *row, DataStructures::List<unsigned> columnIndices); 325 326 void DeleteRow(Row *row); 327 328 void QueryRow(DataStructures::List<unsigned> &inclusionFilterColumnIndices, DataStructures::List<unsigned> &columnIndicesToReturn, unsigned key, Table::Row* row, FilterQuery *inclusionFilters, Table *result); 329 330 // 16 is arbitrary and is the order of the BPlus tree. Higher orders are better for searching while lower orders are better for 331 // Insertions and deletions. 332 DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> rows; 333 334 // Columns in the table. 335 DataStructures::List<ColumnDescriptor> columns; 336 }; 337 } 338 339 #ifdef _MSC_VER 340 #pragma warning( pop ) 341 #endif 342 343 #endif 344