1 #ifndef __TABLE_SERIALIZER_H 2 #define __TABLE_SERIALIZER_H 3 4 #include "RakMemoryOverride.h" 5 #include "DS_Table.h" 6 #include "Export.h" 7 8 namespace RakNet 9 { 10 class BitStream; 11 } 12 13 class RAK_DLL_EXPORT TableSerializer 14 { 15 public: 16 static void SerializeTable(DataStructures::Table *in, RakNet::BitStream *out); 17 static bool DeserializeTable(unsigned char *serializedTable, unsigned int dataLength, DataStructures::Table *out); 18 static bool DeserializeTable(RakNet::BitStream *in, DataStructures::Table *out); 19 static void SerializeColumns(DataStructures::Table *in, RakNet::BitStream *out); 20 static void SerializeColumns(DataStructures::Table *in, RakNet::BitStream *out, DataStructures::List<int> &skipColumnIndices); 21 static bool DeserializeColumns(RakNet::BitStream *in, DataStructures::Table *out); 22 static void SerializeRow(DataStructures::Table::Row *in, unsigned keyIn, const DataStructures::List<DataStructures::Table::ColumnDescriptor> &columns, RakNet::BitStream *out); 23 static void SerializeRow(DataStructures::Table::Row *in, unsigned keyIn, const DataStructures::List<DataStructures::Table::ColumnDescriptor> &columns, RakNet::BitStream *out, DataStructures::List<int> &skipColumnIndices); 24 static bool DeserializeRow(RakNet::BitStream *in, DataStructures::Table *out); 25 static void SerializeCell(RakNet::BitStream *out, DataStructures::Table::Cell *cell, DataStructures::Table::ColumnType columnType); 26 static bool DeserializeCell(RakNet::BitStream *in, DataStructures::Table::Cell *cell, DataStructures::Table::ColumnType columnType); 27 static void SerializeFilterQuery(RakNet::BitStream *in, DataStructures::Table::FilterQuery *query); 28 // Note that this allocates query->cell->c! 29 static bool DeserializeFilterQuery(RakNet::BitStream *out, DataStructures::Table::FilterQuery *query); 30 static void SerializeFilterQueryList(RakNet::BitStream *in, DataStructures::Table::FilterQuery *query, unsigned int numQueries, unsigned int maxQueries); 31 // Note that this allocates queries, cells, and query->cell->c!. Use DeallocateQueryList to free. 32 static bool DeserializeFilterQueryList(RakNet::BitStream *out, DataStructures::Table::FilterQuery **query, unsigned int *numQueries, unsigned int maxQueries, int allocateExtraQueries=0); 33 static void DeallocateQueryList(DataStructures::Table::FilterQuery *query, unsigned int numQueries); 34 }; 35 36 #endif 37 38 // Test code for the table 39 /* 40 #include "LightweightDatabaseServer.h" 41 #include "LightweightDatabaseClient.h" 42 #include "TableSerializer.h" 43 #include "BitStream.h" 44 #include "StringCompressor.h" 45 #include "DS_Table.h" 46 void main(void) 47 { 48 DataStructures::Table table; 49 DataStructures::Table::Row *row; 50 unsigned int dummydata=12345; 51 52 // Add columns Name (string), IP (binary), score (int), and players (int). 53 table.AddColumn("Name", DataStructures::Table::STRING); 54 table.AddColumn("IP", DataStructures::Table::BINARY); 55 table.AddColumn("Score", DataStructures::Table::NUMERIC); 56 table.AddColumn("Players", DataStructures::Table::NUMERIC); 57 table.AddColumn("Empty Test Column", DataStructures::Table::STRING); 58 RakAssert(table.GetColumnCount()==5); 59 row=table.AddRow(0); 60 RakAssert(row); 61 row->UpdateCell(0,"Kevin Jenkins"); 62 row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata); 63 row->UpdateCell(2,5); 64 row->UpdateCell(3,10); 65 //row->UpdateCell(4,"should be unique"); 66 67 row=table.AddRow(1); 68 row->UpdateCell(0,"Kevin Jenkins"); 69 row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata); 70 row->UpdateCell(2,5); 71 row->UpdateCell(3,15); 72 73 row=table.AddRow(2); 74 row->UpdateCell(0,"Kevin Jenkins"); 75 row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata); 76 row->UpdateCell(2,5); 77 row->UpdateCell(3,20); 78 79 row=table.AddRow(3); 80 RakAssert(row); 81 row->UpdateCell(0,"Kevin Jenkins"); 82 row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata); 83 row->UpdateCell(2,15); 84 row->UpdateCell(3,5); 85 row->UpdateCell(4,"col index 4"); 86 87 row=table.AddRow(4); 88 RakAssert(row); 89 row->UpdateCell(0,"Kevin Jenkins"); 90 row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata); 91 //row->UpdateCell(2,25); 92 row->UpdateCell(3,30); 93 //row->UpdateCell(4,"should be unique"); 94 95 row=table.AddRow(5); 96 RakAssert(row); 97 row->UpdateCell(0,"Kevin Jenkins"); 98 row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata); 99 //row->UpdateCell(2,25); 100 row->UpdateCell(3,5); 101 //row->UpdateCell(4,"should be unique"); 102 103 row=table.AddRow(6); 104 RakAssert(row); 105 row->UpdateCell(0,"Kevin Jenkins"); 106 row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata); 107 row->UpdateCell(2,35); 108 //row->UpdateCell(3,40); 109 //row->UpdateCell(4,"should be unique"); 110 111 row=table.AddRow(7); 112 RakAssert(row); 113 row->UpdateCell(0,"Bob Jenkins"); 114 115 row=table.AddRow(8); 116 RakAssert(row); 117 row->UpdateCell(0,"Zack Jenkins"); 118 119 // Test multi-column sorting 120 DataStructures::Table::Row *rows[30]; 121 DataStructures::Table::SortQuery queries[4]; 122 queries[0].columnIndex=0; 123 queries[0].operation=DataStructures::Table::QS_INCREASING_ORDER; 124 queries[1].columnIndex=1; 125 queries[1].operation=DataStructures::Table::QS_INCREASING_ORDER; 126 queries[2].columnIndex=2; 127 queries[2].operation=DataStructures::Table::QS_INCREASING_ORDER; 128 queries[3].columnIndex=3; 129 queries[3].operation=DataStructures::Table::QS_DECREASING_ORDER; 130 table.SortTable(queries, 4, rows); 131 unsigned i; 132 char out[256]; 133 RAKNET_DEBUG_PRINTF("Sort: Ascending except for column index 3\n"); 134 for (i=0; i < table.GetRowCount(); i++) 135 { 136 table.PrintRow(out,256,',',true, rows[i]); 137 RAKNET_DEBUG_PRINTF("%s\n", out); 138 } 139 140 // Test query: 141 // Don't return column 3, and swap columns 0 and 2 142 unsigned columnsToReturn[4]; 143 columnsToReturn[0]=2; 144 columnsToReturn[1]=1; 145 columnsToReturn[2]=0; 146 columnsToReturn[3]=4; 147 DataStructures::Table resultsTable; 148 table.QueryTable(columnsToReturn,4,0,0,&resultsTable); 149 RAKNET_DEBUG_PRINTF("Query: Don't return column 3, and swap columns 0 and 2:\n"); 150 for (i=0; i < resultsTable.GetRowCount(); i++) 151 { 152 resultsTable.PrintRow(out,256,',',true, resultsTable.GetRowByIndex(i)); 153 RAKNET_DEBUG_PRINTF("%s\n", out); 154 } 155 156 // Test filter: 157 // Only return rows with column index 4 empty 158 DataStructures::Table::FilterQuery inclusionFilters[3]; 159 inclusionFilters[0].columnIndex=4; 160 inclusionFilters[0].operation=DataStructures::Table::QF_IS_EMPTY; 161 // inclusionFilters[0].cellValue; // Unused for IS_EMPTY 162 table.QueryTable(0,0,inclusionFilters,1,&resultsTable); 163 RAKNET_DEBUG_PRINTF("Filter: Only return rows with column index 4 empty:\n"); 164 for (i=0; i < resultsTable.GetRowCount(); i++) 165 { 166 resultsTable.PrintRow(out,256,',',true, resultsTable.GetRowByIndex(i)); 167 RAKNET_DEBUG_PRINTF("%s\n", out); 168 } 169 170 // Column 5 empty and column 0 == Kevin Jenkins 171 inclusionFilters[0].columnIndex=4; 172 inclusionFilters[0].operation=DataStructures::Table::QF_IS_EMPTY; 173 inclusionFilters[1].columnIndex=0; 174 inclusionFilters[1].operation=DataStructures::Table::QF_EQUAL; 175 inclusionFilters[1].cellValue.Set("Kevin Jenkins"); 176 table.QueryTable(0,0,inclusionFilters,2,&resultsTable); 177 RAKNET_DEBUG_PRINTF("Filter: Column 5 empty and column 0 == Kevin Jenkins:\n"); 178 for (i=0; i < resultsTable.GetRowCount(); i++) 179 { 180 resultsTable.PrintRow(out,256,',',true, resultsTable.GetRowByIndex(i)); 181 RAKNET_DEBUG_PRINTF("%s\n", out); 182 } 183 184 RakNet::BitStream bs; 185 RAKNET_DEBUG_PRINTF("PreSerialize:\n"); 186 for (i=0; i < table.GetRowCount(); i++) 187 { 188 table.PrintRow(out,256,',',true, table.GetRowByIndex(i)); 189 RAKNET_DEBUG_PRINTF("%s\n", out); 190 } 191 StringCompressor::AddReference(); 192 TableSerializer::Serialize(&table, &bs); 193 TableSerializer::Deserialize(&bs, &table); 194 StringCompressor::RemoveReference(); 195 RAKNET_DEBUG_PRINTF("PostDeserialize:\n"); 196 for (i=0; i < table.GetRowCount(); i++) 197 { 198 table.PrintRow(out,256,',',true, table.GetRowByIndex(i)); 199 RAKNET_DEBUG_PRINTF("%s\n", out); 200 } 201 int a=5; 202 } 203 */ 204