/src/main.c

http://github.com/breckinloggins/ZombieSQL · C · 426 lines · 301 code · 95 blank · 30 comment · 28 complexity · 761f0894ece525fd72845d6a28a3f403 MD5 · raw file

  1. //
  2. // main.c
  3. // ZombieSQL
  4. //
  5. // Created by Benjamin Loggins on 4/20/11.
  6. // Copyright 2011 GreatFoundry. All rights reserved.
  7. //
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include "zdb.h"
  12. static int testLevel = 0;
  13. #define TEST_INDENT() { int i = 0; while (i++ < testLevel) { printf("\t"); } }
  14. #define TEST_START(name) { TEST_INDENT(); printf("Testing %s\n", name); testLevel++; }
  15. #define TEST_ASSERT(test, stmt) { if (!(stmt)) { TEST_INDENT(); printf("!!FAIL!! (%s)\n", test); exit(1); } }
  16. #define TEST_PASS() { testLevel--; TEST_INDENT(); printf("PASS\n"); }
  17. void CreateTestRow(ZdbTable* table, char* name, char* age, char* salary, char* active)
  18. {
  19. TEST_START("CreateTestRow");
  20. ZdbRow* r;
  21. TEST_ASSERT("Insert row", !ZdbEngineInsertRow(table, 5, &r));
  22. TEST_ASSERT("Update row", ZdbEngineUpdateRow(table, r, 5, NULL, name, age, salary, active) == 1);
  23. TEST_PASS();
  24. }
  25. ZdbDatabase* CreateTestDatabase()
  26. {
  27. TEST_START("CreateTestDatabase");
  28. ZdbDatabase* db = NULL;
  29. TEST_ASSERT("ZdbEngineCreateDB", !ZdbEngineCreateDB("Company", &db));
  30. ZdbColumn** columns = malloc(5*sizeof(ZdbColumn*));
  31. TEST_ASSERT("Create ID Column", !ZdbEngineCreateColumn("ID", ZdbStandardTypes->intType, 1, &(columns[0])));
  32. TEST_ASSERT("Create Name Column", !ZdbEngineCreateColumn("Name", ZdbStandardTypes->varcharType, 0, &(columns[1])));
  33. TEST_ASSERT("Create Age Column", !ZdbEngineCreateColumn("Age", ZdbStandardTypes->intType, 0, &(columns[2])));
  34. TEST_ASSERT("Create Salary Column", !ZdbEngineCreateColumn("Salary", ZdbStandardTypes->floatType, 0, &(columns[3])));
  35. TEST_ASSERT("Create Active Column", !ZdbEngineCreateColumn("Active", ZdbStandardTypes->booleanType, 0, &(columns[4])));
  36. ZdbTable* t = NULL;
  37. TEST_ASSERT("Create Employeees Table", !ZdbEngineCreateTable(db, "Employees", 5, columns, &t));
  38. CreateTestRow(t, "Breckin", "30", "34000.0", "1");
  39. CreateTestRow(t, "Bob", "22", "15600.0", "1");
  40. CreateTestRow(t, "Jane", "45", "45000.0", "1");
  41. CreateTestRow(t, "John", "35", "95600.0", "0");
  42. /* Testing that the autoincrement worked */
  43. ZdbQuery* q;
  44. ZdbRecordset* rs;
  45. TEST_ASSERT("create query", !ZdbQueryCreate(db, &q));
  46. TEST_ASSERT("add table", !ZdbQueryAddTable(q, db->tables[0]));
  47. TEST_ASSERT("execute", !ZdbQueryExecute(q, &rs));
  48. int lastId = -1;
  49. while (ZdbQueryNextResult(rs))
  50. {
  51. int id;
  52. TEST_ASSERT("get value", !ZdbQueryGetInt(rs, 0, &id));
  53. TEST_ASSERT("autoincrement check", lastId != id);
  54. lastId = id;
  55. }
  56. ZdbQueryFree(q);
  57. TEST_PASS();
  58. return db;
  59. }
  60. void PrintQueryResults(ZdbRecordset* rs)
  61. {
  62. while(ZdbQueryNextResult(rs))
  63. {
  64. int id = 0;
  65. char* name;
  66. int age = 0;
  67. float salary = 0.0f;
  68. int active = 0;
  69. ZdbQueryGetInt(rs, 0, &id);
  70. ZdbQueryGetString(rs, 1, &name);
  71. ZdbQueryGetInt(rs, 2, &age);
  72. ZdbQueryGetFloat(rs, 3, &salary);
  73. ZdbQueryGetBoolean(rs, 4, &active);
  74. printf("Employee %d (%s/%d): $%.2f [%s]\n",
  75. id,
  76. name,
  77. age,
  78. salary,
  79. active? "ACTIVE" : "TERMINATED");
  80. }
  81. }
  82. void TestTypeCopyValue()
  83. {
  84. int i1, i2;
  85. float f1, f2;
  86. int b1, b2;
  87. char s1[ZDB_LIMIT_VARCHAR], s2[ZDB_LIMIT_VARCHAR];
  88. TEST_START("TestTypeCopyValue");
  89. i1 = 10; i2 = 0;
  90. TEST_ASSERT("int copy", !ZdbTypeCopy(ZdbStandardTypes->intType, &i2, &i1));
  91. TEST_ASSERT("int check", i2 == i1);
  92. f1 = 11.2; f2 = 0;
  93. TEST_ASSERT("float copy", !ZdbTypeCopy(ZdbStandardTypes->floatType, &f2, &f1));
  94. TEST_ASSERT("float check", abs(f2 - f1) < 0.1);
  95. b1 = 1; b2 = 0;
  96. TEST_ASSERT("boolean copy", !ZdbTypeCopy(ZdbStandardTypes->booleanType, &b2, &b1));
  97. TEST_ASSERT("boolean check", b1 == b2);
  98. strcpy(s1, "foo"), strcpy(s2, "");
  99. TEST_ASSERT("varchar copy", !ZdbTypeCopy(ZdbStandardTypes->varcharType, &s2, &s1));
  100. TEST_ASSERT("varchar check", !strcmp(s2, "foo"));
  101. TEST_PASS();
  102. }
  103. void TestTypeSystem()
  104. {
  105. TEST_START("Type System");
  106. TEST_ASSERT("Initialize", !ZdbTypeInitialize());
  107. /* TODO: Repeat all tests with all builtin types */
  108. // Test comparisons
  109. int a, b, res;
  110. a = 1, b = 1;
  111. TEST_ASSERT("int compare ==", !ZdbTypeCompare(ZdbStandardTypes->intType, &a, &b, &res));
  112. TEST_ASSERT("int == check", !res);
  113. a = 1, b = 2;
  114. TEST_ASSERT("int compare <", !ZdbTypeCompare(ZdbStandardTypes->intType, &a, &b, &res));
  115. TEST_ASSERT("int < check", res < 0);
  116. a = 2, b = 1;
  117. TEST_ASSERT("int compare >", !ZdbTypeCompare(ZdbStandardTypes->intType, &a, &b, &res));
  118. TEST_ASSERT("int > check", res > 0);
  119. // Test sizeof
  120. size_t size;
  121. TEST_ASSERT("sizeof", !ZdbTypeSizeof(ZdbStandardTypes->intType, NULL, &size));
  122. TEST_ASSERT("sizeof check", size == sizeof(int));
  123. TEST_ASSERT("sizeof unsupported", ZdbTypeSizeof(ZdbStandardTypes->intType, &a, &size) == ZDB_RESULT_UNSUPPORTED);
  124. // Test From String
  125. TEST_ASSERT("from string", !ZdbTypeFromString(ZdbStandardTypes->intType, "42", &a));
  126. TEST_ASSERT("from string check", a == 42);
  127. // Test To String
  128. char str[7] = {0};
  129. a = 12345;
  130. size = 0;
  131. TEST_ASSERT("to string", !ZdbTypeToString(ZdbStandardTypes->intType, &a, &size, NULL));
  132. TEST_ASSERT("to string check", size == 5);
  133. TEST_ASSERT("to string2", !ZdbTypeToString(ZdbStandardTypes->intType, &a, &size, str));
  134. TEST_ASSERT("to string2 check", !strcmp(str, "12345"));
  135. // Test Next Value
  136. a = 42;
  137. TEST_ASSERT("next value", !ZdbTypeNextValue(ZdbStandardTypes->intType, &a, &b));
  138. TEST_ASSERT("next value check", b == 43);
  139. TestTypeCopyValue();
  140. TEST_PASS();
  141. }
  142. void TestBasicQuery(ZdbDatabase* db)
  143. {
  144. TEST_START("basic query");
  145. ZdbQuery* q = NULL;
  146. TEST_ASSERT("query create", !ZdbQueryCreate(db, &q));
  147. TEST_ASSERT("add table", !ZdbQueryAddTable(q, db->tables[0]));
  148. ZdbRecordset* rs = NULL;
  149. TEST_ASSERT("execute", !ZdbQueryExecute(q, &rs));
  150. int count = 0;
  151. while(ZdbQueryNextResult(rs))
  152. {
  153. ++count;
  154. }
  155. TEST_ASSERT("has results", count > 0);
  156. ZdbQueryFree(q);
  157. TEST_PASS();
  158. }
  159. void AssertResultContains(ZdbRecordset* rs, int column, const char* value, ZdbType* valueType, int checkCount)
  160. {
  161. int count = 0;
  162. char str[255];
  163. while (ZdbQueryNextResult(rs))
  164. {
  165. void* v;
  166. size_t length = 255;
  167. TEST_ASSERT("get value", !ZdbQueryGetValue(rs, column, valueType, &v));
  168. TEST_ASSERT("to string", !ZdbTypeToString(valueType, v, &length, str));
  169. if (!strcmp(value, str))
  170. {
  171. count++;
  172. }
  173. }
  174. sprintf(str, "Column %d == %s (%d rows [%d expected])", column, value, count, checkCount);
  175. TEST_ASSERT(str, count == checkCount);
  176. }
  177. void TestOneConditionQuery(ZdbDatabase* db, int column, ZdbQueryConditionType queryType, const char* value, ZdbType* valueType, const char* checkValue, int checkCount)
  178. {
  179. char str[255];
  180. char op[3];
  181. switch(queryType)
  182. {
  183. case ZDB_QUERY_CONDITION_EQ:
  184. strcpy(op, "=");
  185. break;
  186. case ZDB_QUERY_CONDITION_NE:
  187. strcpy(op, "<>");
  188. break;
  189. case ZDB_QUERY_CONDITION_LT:
  190. strcpy(op, "<");
  191. break;
  192. case ZDB_QUERY_CONDITION_GT:
  193. strcpy(op, ">");
  194. break;
  195. case ZDB_QUERY_CONDITION_LTE:
  196. strcpy(op, "<=");
  197. break;
  198. case ZDB_QUERY_CONDITION_GTE:
  199. strcpy(op, ">=");
  200. break;
  201. default:
  202. strcpy(op, "??");
  203. break;
  204. }
  205. sprintf(str, "OneConditionQuery (%s %s %s)", db->tables[0]->columns[column]->name, op, value);
  206. TEST_START(str);
  207. ZdbQuery* q = NULL;
  208. TEST_ASSERT("create query", !ZdbQueryCreate(db, &q));
  209. TEST_ASSERT("add table", !ZdbQueryAddTable(q, db->tables[0]));
  210. TEST_ASSERT("add condition", !ZdbQueryAddCondition(q, queryType, column, valueType, value));
  211. ZdbRecordset* rs = NULL;
  212. TEST_ASSERT("execute query", !ZdbQueryExecute(q, &rs));
  213. AssertResultContains(rs, column, checkValue, valueType, checkCount);
  214. ZdbQueryFree(q);
  215. TEST_PASS();
  216. }
  217. void UpdateRowTestHelper(ZdbDatabase* db, int table, int queryColumn, const char* queryValue, int updateColumn, void* updateValue)
  218. {
  219. /* Most of this code will likely turn into the Update command code */
  220. ZdbType* queryColumnType = db->tables[table]->columns[queryColumn]->type;
  221. ZdbType* updateColumnType = db->tables[table]->columns[updateColumn]->type;
  222. /* Get some names of things to make diagnostic messages less painful */
  223. char tableName[ZDB_LIMIT_VARCHAR], columnName[ZDB_LIMIT_VARCHAR], originalValueString[ZDB_LIMIT_VARCHAR], updateValueString[ZDB_LIMIT_VARCHAR], testName[ZDB_LIMIT_VARCHAR];
  224. strcpy(tableName, db->tables[table]->name);
  225. strcpy(columnName, db->tables[table]->columns[updateColumn]->name);
  226. size_t length = ZDB_LIMIT_VARCHAR;
  227. ZdbTypeToString(updateColumnType, updateValue, &length, updateValueString);
  228. sprintf(testName, "Update %s(%s) [QUERY]", tableName, columnName);
  229. TEST_START(testName);
  230. ZdbQuery* q;
  231. ZdbRecordset* rs;
  232. TEST_ASSERT("create query", !ZdbQueryCreate(db, &q));
  233. TEST_ASSERT("add table", !ZdbQueryAddTable(q, db->tables[table]));
  234. TEST_ASSERT("add condition", !ZdbQueryAddCondition(q, ZDB_QUERY_CONDITION_EQ, queryColumn, queryColumnType, queryValue));
  235. TEST_ASSERT("execute query", !ZdbQueryExecute(q, &rs));
  236. TEST_ASSERT("has results", ZdbQueryNextResult(rs));
  237. /* Get the current value so we can print it*/
  238. void* originalValue;
  239. length = ZDB_LIMIT_VARCHAR;
  240. TEST_ASSERT("get value", !ZdbQueryGetValue(rs, updateColumn, updateColumnType, &originalValue));
  241. TEST_ASSERT("to string", !ZdbTypeToString(updateColumnType, originalValue, &length, originalValueString));
  242. TEST_PASS();
  243. sprintf(testName, "Update %s => %s", originalValueString, updateValueString);
  244. TEST_START(testName);
  245. int rowId = -1;
  246. /* Collect the values for this row as a string */
  247. void** values = calloc(db->tables[table]->columnCount, sizeof(void*));
  248. int i;
  249. for (i = 0; i < db->tables[table]->columnCount; i++)
  250. {
  251. void* value;
  252. ZdbType* thisType = db->tables[table]->columns[i]->type;
  253. TEST_ASSERT("get value", !ZdbQueryGetValue(rs, i, thisType, &value));
  254. if (rowId == -1 && db->tables[table]->columns[i]->autoincrement)
  255. {
  256. /* For our test DB, we can assume the first auto increment column is an
  257. int row id that matches the row index */
  258. rowId = *(int*)value;
  259. }
  260. if (i == updateColumn)
  261. {
  262. values[i] = updateValue;
  263. }
  264. else
  265. {
  266. values[i] = value;
  267. }
  268. }
  269. ZdbRow* row = db->tables[table]->rows[rowId];
  270. TEST_ASSERT("update row values", ZdbEngineUpdateRowValues(db->tables[table], row, db->tables[table]->columnCount, values) == 1);
  271. void* updatedValue;
  272. TEST_ASSERT("get value", !ZdbQueryGetValue(rs, updateColumn, updateColumnType, &updatedValue));
  273. int result = 0;
  274. TEST_ASSERT("type compare", !ZdbTypeCompare(updateColumnType, updateValue, updatedValue, &result));
  275. TEST_ASSERT("update check", result == 0);
  276. free(values);
  277. ZdbQueryFree(q);
  278. TEST_PASS();
  279. }
  280. void TestBasicRowUpdate(ZdbDatabase* db)
  281. {
  282. /* Legal wants Bob's official name changed to Robert in the DB */
  283. int i = 1;
  284. UpdateRowTestHelper(db, 0, 0, "1", 1, "Robert");
  285. /* John gets rehired */
  286. i = 3;
  287. int active = 1;
  288. UpdateRowTestHelper(db, 0, 0, "3", 4, &active);
  289. /* Jane got older */
  290. i = 2;
  291. int age = 46;
  292. UpdateRowTestHelper(db, 0, 0, "2", 2, &age);
  293. /* And I got a raise! */
  294. i = 0;
  295. float salary = 80000;
  296. UpdateRowTestHelper(db, 0, 0, "0", 3, &salary);
  297. }
  298. int main (int argc, const char * argv[])
  299. {
  300. if (ZdbTypeInitialize() != ZDB_RESULT_SUCCESS)
  301. {
  302. printf("Could not initialize type system\n");
  303. }
  304. TestTypeSystem();
  305. ZdbDatabase* db = CreateTestDatabase();
  306. TestBasicQuery(db);
  307. /* EQ */
  308. TestOneConditionQuery(db, 0, ZDB_QUERY_CONDITION_EQ, "1", ZdbStandardTypes->intType, "1", 1);
  309. TestOneConditionQuery(db, 1, ZDB_QUERY_CONDITION_EQ, "Jane", ZdbStandardTypes->varcharType, "Jane", 1);
  310. TestOneConditionQuery(db, 2, ZDB_QUERY_CONDITION_EQ, "30", ZdbStandardTypes->intType, "30", 1);
  311. TestOneConditionQuery(db, 3, ZDB_QUERY_CONDITION_EQ, "34000.000000", ZdbStandardTypes->floatType, "34000.000000", 1);
  312. TestOneConditionQuery(db, 4, ZDB_QUERY_CONDITION_EQ, "0", ZdbStandardTypes->booleanType, "0", 1);
  313. TestOneConditionQuery(db, 4, ZDB_QUERY_CONDITION_EQ, "1", ZdbStandardTypes->booleanType, "1", 3);
  314. /* NE */
  315. TestOneConditionQuery(db, 4, ZDB_QUERY_CONDITION_NE, "0", ZdbStandardTypes->booleanType, "1", 3);
  316. /* LT */
  317. TestOneConditionQuery(db, 2, ZDB_QUERY_CONDITION_LT, "30", ZdbStandardTypes->intType, "22", 1);
  318. TestOneConditionQuery(db, 1, ZDB_QUERY_CONDITION_LT, "Breckin", ZdbStandardTypes->varcharType, "Bob", 1);
  319. /* GT */
  320. TestOneConditionQuery(db, 3, ZDB_QUERY_CONDITION_GT, "45000.0", ZdbStandardTypes->floatType, "95600.000000", 1);
  321. TestOneConditionQuery(db, 4, ZDB_QUERY_CONDITION_GT, "0", ZdbStandardTypes->booleanType, "1", 3);
  322. /* LTE */
  323. TestOneConditionQuery(db, 2, ZDB_QUERY_CONDITION_LTE, "22", ZdbStandardTypes->intType, "22", 1);
  324. TestOneConditionQuery(db, 0, ZDB_QUERY_CONDITION_LTE, "-1", ZdbStandardTypes->intType, "-1", 0);
  325. /* GTE */
  326. TestOneConditionQuery(db, 2, ZDB_QUERY_CONDITION_GTE, "45", ZdbStandardTypes->intType, "45", 1);
  327. TestOneConditionQuery(db, 4, ZDB_QUERY_CONDITION_GTE, "1", ZdbStandardTypes->booleanType, "1", 3);
  328. TestBasicRowUpdate(db);
  329. ZdbEngineDropDB(db);
  330. return 0;
  331. }