BOOL CDbxKV::MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) { DBEventSortingKey keyVal = { ccSub->contactID, 0, 0 }, insVal = { ccMeta->contactID, 0, 0 }; ham_key_t key = { sizeof(keyVal), &keyVal }, key2 = { sizeof(insVal), &insVal }; ham_record_t data = { 0 }; cursor_ptr cursor(m_dbEventsSort); if (ham_cursor_find(cursor, &key, &data, HAM_FIND_GT_MATCH) != HAM_SUCCESS) return 0; do { DBEventSortingKey *pKey = (DBEventSortingKey*)key.data; if (pKey->dwContactId != ccSub->contactID) break; insVal.ts = pKey->ts; insVal.dwEventId = pKey->dwEventId; ham_db_insert(m_dbEventsSort, NULL, &key2, &data, HAM_OVERWRITE); ccMeta->dbc.dwEventCount++; } while (ham_cursor_move(cursor, &key, &data, HAM_CURSOR_NEXT) == HAM_SUCCESS); // now update the number of events in a metacontact ham_key_t keyc = { sizeof(int), &ccMeta->contactID }; ham_record_t datac = { sizeof(ccMeta->dbc), &ccMeta->dbc }; ham_db_insert(m_dbContacts, NULL, &keyc, &datac, HAM_OVERWRITE); return 0; }
// will create the offset if it needs to DWORD CDbxKV::GetModuleNameOfs(const char *szName) { DWORD ofsExisting = FindExistingModuleNameOfs(szName); if (ofsExisting) return ofsExisting; if (m_bReadOnly) return 0; int nameLen = (int)strlen(szName); // need to create the module name int newIdx = ++m_maxModuleID; DBModuleName *pmod = (DBModuleName*)_alloca(sizeof(DBModuleName) + nameLen); pmod->dwSignature = DBMODULENAME_SIGNATURE; pmod->cbName = (char)nameLen; strcpy(pmod->name, szName); ham_key_t key = { sizeof(int), &newIdx }; ham_record_t rec = { sizeof(DBModuleName) + nameLen, pmod }; ham_db_insert(m_dbModules, NULL, &key, &rec, HAM_OVERWRITE); // add to cache char *mod = (char*)HeapAlloc(m_hModHeap, 0, nameLen + 1); strcpy(mod, szName); AddToList(mod, newIdx); // quit return -1; }
/** Inserts a key/record pair. */ void insert(txn *t, key *k, record *r, uint32_t flags = 0) { ham_status_t st = ham_db_insert(m_db, t ? t->get_handle() : 0, k ? k->get_handle() : 0, r ? r->get_handle() : 0, flags); if (st) throw error(st); }
STDMETHODIMP_(MCONTACT) CDbxKV::AddContact() { DWORD dwContactId; { mir_cslock lck(m_csDbAccess); dwContactId = m_dwMaxContactId++; DBCachedContact *cc = m_cache->AddContactToCache(dwContactId); cc->dbc.dwSignature = DBCONTACT_SIGNATURE; ham_key_t key = { sizeof(MCONTACT), &dwContactId }; ham_record_t data = { sizeof(cc->dbc), &cc->dbc }; ham_db_insert(m_dbContacts, NULL, &key, &data, HAM_OVERWRITE); } NotifyEventHooks(hContactAddedEvent, dwContactId, 0); return dwContactId; }
void copy_db(ham_db_t *source, ham_db_t *dest) { ham_cursor_t *cursor; /* hamsterdb cursor object */ ham_status_t st; ham_key_t key; ham_record_t rec; memset(&key, 0, sizeof(key)); memset(&rec, 0, sizeof(rec)); /* create a new cursor */ st = ham_cursor_create(&cursor, source, 0, 0); if (st) error("ham_cursor_create", st); /* get a cursor to the source database */ st = ham_cursor_move(cursor, &key, &rec, HAM_CURSOR_FIRST); if (st == HAM_KEY_NOT_FOUND) { printf("database is empty!\n"); return; } else if (st) error("ham_cursor_move", st); do { /* insert this element into the new database */ st = ham_db_insert(dest, 0, &key, &rec, HAM_DUPLICATE); if (st) error("ham_db_insert", st); /* give some feedback to the user */ printf("."); /* fetch the next item, and repeat till we've reached the end * of the database */ st = ham_cursor_move(cursor, &key, &rec, HAM_CURSOR_NEXT); if (st && st != HAM_KEY_NOT_FOUND) error("ham_cursor_move", st); } while (st == 0); /* clean up and return */ ham_cursor_close(cursor); }
STDMETHODIMP_(BOOL) CDbxKV::WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) { if (dbcws == NULL || dbcws->szSetting == NULL || dbcws->szModule == NULL || m_bReadOnly) return 1; // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name int settingNameLen = (int)strlen(dbcws->szSetting); int moduleNameLen = (int)strlen(dbcws->szModule); if (settingNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("WriteContactSetting() got a > 255 setting name length. \n"); #endif return 1; } if (moduleNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("WriteContactSetting() got a > 255 module name length. \n"); #endif return 1; } // used for notifications DBCONTACTWRITESETTING dbcwNotif = *dbcws; if (dbcwNotif.value.type == DBVT_WCHAR) { if (dbcwNotif.value.pszVal != NULL) { char* val = mir_utf8encodeW(dbcwNotif.value.pwszVal); if (val == NULL) return 1; dbcwNotif.value.pszVal = (char*)alloca(strlen(val) + 1); strcpy(dbcwNotif.value.pszVal, val); mir_free(val); dbcwNotif.value.type = DBVT_UTF8; } else return 1; } if (dbcwNotif.szModule == NULL || dbcwNotif.szSetting == NULL) return 1; DBCONTACTWRITESETTING dbcwWork = dbcwNotif; mir_ptr<BYTE> pEncoded(NULL); bool bIsEncrypted = false; switch (dbcwWork.value.type) { case DBVT_BYTE: case DBVT_WORD: case DBVT_DWORD: break; case DBVT_ASCIIZ: case DBVT_UTF8: bIsEncrypted = m_bEncrypted || IsSettingEncrypted(dbcws->szModule, dbcws->szSetting); LBL_WriteString: if (dbcwWork.value.pszVal == NULL) return 1; dbcwWork.value.cchVal = (WORD)strlen(dbcwWork.value.pszVal); if (bIsEncrypted) { size_t len; BYTE *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len); if (pResult != NULL) { pEncoded = dbcwWork.value.pbVal = pResult; dbcwWork.value.cpbVal = (WORD)len; dbcwWork.value.type = DBVT_ENCRYPTED; } } break; case DBVT_UNENCRYPTED: dbcwNotif.value.type = dbcwWork.value.type = DBVT_UTF8; goto LBL_WriteString; case DBVT_BLOB: case DBVT_ENCRYPTED: if (dbcwWork.value.pbVal == NULL) return 1; break; default: return 1; } mir_cslockfull lck(m_csDbAccess); char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen); // we don't cache blobs and passwords if (dbcwWork.value.type != DBVT_BLOB && dbcwWork.value.type != DBVT_ENCRYPTED && !bIsEncrypted) { DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); if (pCachedValue != NULL) { bool bIsIdentical = false; if (pCachedValue->type == dbcwWork.value.type) { switch (dbcwWork.value.type) { case DBVT_BYTE: bIsIdentical = pCachedValue->bVal == dbcwWork.value.bVal; break; case DBVT_WORD: bIsIdentical = pCachedValue->wVal == dbcwWork.value.wVal; break; case DBVT_DWORD: bIsIdentical = pCachedValue->dVal == dbcwWork.value.dVal; break; case DBVT_UTF8: case DBVT_ASCIIZ: bIsIdentical = strcmp(pCachedValue->pszVal, dbcwWork.value.pszVal) == 0; break; } if (bIsIdentical) return 0; } m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue); } if (szCachedSettingName[-1] != 0) { lck.unlock(); NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwWork); return 0; } } else m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); DBSettingSortingKey keySearch; keySearch.dwContactID = contactID; keySearch.dwOfsModule = GetModuleNameOfs(dbcws->szModule); strncpy_s(keySearch.szSettingName, dbcws->szSetting, _TRUNCATE); ham_key_t key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }; ham_record_t rec = { 0 }; switch (dbcwWork.value.type) { case DBVT_BYTE: rec.size = 2; break; case DBVT_WORD: rec.size = 3; break; case DBVT_DWORD: rec.size = 5; break; case DBVT_ASCIIZ: case DBVT_UTF8: rec.size = 3 + dbcwWork.value.cchVal; break; case DBVT_BLOB: case DBVT_ENCRYPTED: rec.size = 3 + dbcwWork.value.cpbVal; break; default: return 1; } rec.data = _alloca(rec.size); BYTE *pBlob = (BYTE*)rec.data; *pBlob++ = dbcwWork.value.type; switch (dbcwWork.value.type) { case DBVT_BYTE: *pBlob = dbcwWork.value.bVal; break; case DBVT_WORD: *(WORD*)pBlob = dbcwWork.value.wVal; break; case DBVT_DWORD: *(DWORD*)pBlob = dbcwWork.value.dVal; break; case DBVT_ASCIIZ: case DBVT_UTF8: *(WORD*)pBlob = dbcwWork.value.cchVal; memcpy(pBlob+2, dbcwWork.value.pszVal, dbcwWork.value.cchVal); break; case DBVT_BLOB: case DBVT_ENCRYPTED: *(WORD*)pBlob = dbcwWork.value.cpbVal; memcpy(pBlob+2, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); } ham_db_insert(m_dbSettings, NULL, &key, &rec, HAM_OVERWRITE); lck.unlock(); // notify NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif); return 0; }
int main(int argc, char **argv) { int i; ham_status_t st; /* status variable */ ham_env_t *env; /* hamsterdb Environment object */ ham_db_t *db; /* hamsterdb Database object */ ham_key_t key = {0}; /* the structure for a key */ ham_record_t record = {0}; /* the structure for a record */ /* * Connect to the server which should listen at 8080. The server is * implemented in server1.c. */ st = ham_env_create(&env, "ham://localhost:8080/env1.db", 0, 0, 0); if (st != HAM_SUCCESS) error("ham_env_create", st); /* now open a Database in this Environment */ st = ham_env_open_db(env, &db, 13, 0, 0); if (st != HAM_SUCCESS) error("ham_env_open_db", st); /* now we can insert, delete or lookup values in the database */ for (i = 0; i < LOOP; i++) { key.data = &i; key.size = sizeof(i); record.size = key.size; record.data = key.data; st = ham_db_insert(db, 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_insert", st); } /* now lookup all values */ for (i = 0; i < LOOP; i++) { key.data = &i; key.size = sizeof(i); st = ham_db_find(db, 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_find", st); /* check if the value is ok */ if (*(int *)record.data != i) { printf("ham_db_find() ok, but returned bad value\n"); return (-1); } } /* erase everything */ for (i = 0; i < LOOP; i++) { key.data = &i; key.size = sizeof(i); st = ham_db_erase(db, 0, &key, 0); if (st != HAM_SUCCESS) error("ham_db_erase", st); } /* and make sure that the database is empty */ for (i = 0; i < LOOP; i++) { key.data = &i; key.size = sizeof(i); st = ham_db_find(db, 0, &key, &record, 0); if (st != HAM_KEY_NOT_FOUND) error("ham_db_find", st); } /* close the database handle */ st = ham_db_close(db, 0); if (st != HAM_SUCCESS) error("ham_db_close", st); /* close the environment handle */ st = ham_env_close(env, 0); if (st != HAM_SUCCESS) error("ham_env_close", st); printf("success!\n"); return (0); }
int main(int argc, char **argv) { int i; ham_status_t st; /* status variable */ ham_db_t *db[MAX_DBS]; /* hamsterdb database objects */ ham_env_t *env; /* hamsterdb environment */ ham_cursor_t *cursor[MAX_DBS]; /* a cursor for each database */ ham_key_t key, cust_key, ord_key; ham_record_t record, cust_record, ord_record; customer_t customers[MAX_CUSTOMERS] = { { 1, "Alan Antonov Corp." }, { 2, "Barry Broke Inc." }, { 3, "Carl Caesar Lat." }, { 4, "Doris Dove Brd." } }; order_t orders[MAX_ORDERS] = { { 1, 1, "Joe" }, { 2, 1, "Tom" }, { 3, 3, "Joe" }, { 4, 4, "Tom" }, { 5, 3, "Ben" }, { 6, 3, "Ben" }, { 7, 4, "Chris" }, { 8, 1, "Ben" } }; memset(&key, 0, sizeof(key)); memset(&record, 0, sizeof(record)); memset(&cust_key, 0, sizeof(cust_key)); memset(&cust_record, 0, sizeof(cust_record)); memset(&ord_key, 0, sizeof(ord_key)); memset(&ord_record, 0, sizeof(ord_record)); /* Now create a new hamsterdb Environment */ st = ham_env_create(&env, "test.db", 0, 0664, 0); if (st != HAM_SUCCESS) error("ham_env_create", st); /* * Then create the two Databases in this Environment; each Database * has a name - the first is our "customer" Database, the second * is for the "orders" */ st = ham_env_create_db(env, &db[0], DBNAME_CUSTOMER, 0, 0); if (st != HAM_SUCCESS) error("ham_env_create_db (customer)", st); st = ham_env_create_db(env, &db[1], DBNAME_ORDER, 0, 0); if (st != HAM_SUCCESS) error("ham_env_create_db (order)", st); /* Create a Cursor for each Database */ for (i = 0; i < MAX_DBS; i++) { st = ham_cursor_create(&cursor[i], db[i], 0, 0); if (st != HAM_SUCCESS) { printf("ham_cursor_create() failed with error %d\n", st); return (-1); } } /* Insert a few customers in the first database */ for (i = 0; i < MAX_CUSTOMERS; i++) { key.size = sizeof(int); key.data = &customers[i].id; record.size = sizeof(customer_t); record.data = &customers[i]; st = ham_db_insert(db[0], 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_insert (customer)", st); } /* And now the orders in the second database */ for (i = 0; i < MAX_ORDERS; i++) { key.size = sizeof(int); key.data = &orders[i].id; record.size = sizeof(order_t); record.data = &orders[i]; st = ham_db_insert(db[1], 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_insert (order)", st); } /* * To demonstrate even more functions: close all objects, then * re-open the environment and the two databases. * * Note that ham_env_close automatically calls ham_db_close on all * databases. */ for (i = 0; i < MAX_DBS; i++) { st = ham_cursor_close(cursor[i]); if (st != HAM_SUCCESS) error("ham_cursor_close", st); } st = ham_env_close(env, 0); if (st != HAM_SUCCESS) error("ham_env_close", st); /* Now reopen the environment and the databases */ st = ham_env_open(&env, "test.db", 0, 0); if (st != HAM_SUCCESS) error("ham_env_open", st); st = ham_env_open_db(env, &db[0], DBNAME_CUSTOMER, 0, 0); if (st != HAM_SUCCESS) error("ham_env_open_db (customer)", st); st = ham_env_open_db(env, &db[1], DBNAME_ORDER, 0, 0); if (st != HAM_SUCCESS) error("ham_env_open_db (order)", st); /* Re-create a cursor for each database */ for (i = 0; i < MAX_DBS; i++) { st = ham_cursor_create(&cursor[i], db[i], 0, 0); if (st != HAM_SUCCESS) { printf("ham_cursor_create() failed with error %d\n", st); return (-1); } } /* * Now start the query - we want to dump each customer with his * orders * * We have a loop with two cursors - the first cursor looping over * the database with customers, the second loops over the orders. */ while (1) { customer_t *customer; st = ham_cursor_move(cursor[0], &cust_key, &cust_record, HAM_CURSOR_NEXT); if (st != HAM_SUCCESS) { /* reached end of the database? */ if (st == HAM_KEY_NOT_FOUND) break; else error("ham_cursor_next(customer)", st); } customer = (customer_t *)cust_record.data; /* print the customer id and name */ printf("customer %d ('%s')\n", customer->id, customer->name); /* * The inner loop prints all orders of this customer. Move the * cursor to the first entry. */ st = ham_cursor_move(cursor[1], &ord_key, &ord_record, HAM_CURSOR_FIRST); if (st != HAM_SUCCESS) { /* reached end of the database? */ if (st == HAM_KEY_NOT_FOUND) continue; else error("ham_cursor_next(order)", st); } do { order_t *order = (order_t *)ord_record.data; /* print this order, if it belongs to the current customer */ if (order->customer_id == customer->id) printf(" order: %d (assigned to %s)\n", order->id, order->assignee); st = ham_cursor_move(cursor[1], &ord_key, &ord_record, HAM_CURSOR_NEXT); if (st != HAM_SUCCESS) { /* reached end of the database? */ if (st == HAM_KEY_NOT_FOUND) break; else error("ham_cursor_next(order)", st); } } while (1); } /* * Now close the environment handle; the flag HAM_AUTO_CLEANUP will * automatically close all databases and cursors */ st = ham_env_close(env, HAM_AUTO_CLEANUP); if (st != HAM_SUCCESS) error("ham_env_close", st); printf("success!\n"); return (0); }
int main(int argc, char **argv) { uint32_t i; ham_status_t st; /* status variable */ ham_env_t *env; /* hamsterdb environment object */ ham_db_t *db; /* hamsterdb database object */ ham_key_t key = {0}; /* the structure for a key */ ham_record_t record = {0}; /* the structure for a record */ ham_parameter_t params[] = { /* parameters for ham_env_create_db */ {HAM_PARAM_KEY_TYPE, HAM_TYPE_UINT32}, {HAM_PARAM_RECORD_SIZE, sizeof(uint32_t)}, {0, } }; /* First create a new hamsterdb Environment */ st = ham_env_create(&env, "test.db", 0, 0664, 0); if (st != HAM_SUCCESS) error("ham_create", st); /* And in this Environment we create a new Database for uint32-keys * and uint32-records. */ st = ham_env_create_db(env, &db, DATABASE_NAME, 0, ¶ms[0]); if (st != HAM_SUCCESS) error("ham_create", st); /* * now we can insert, delete or lookup values in the database * * for our test program, we just insert a few values, then look them * up, then delete them and try to look them up again (which will fail). */ for (i = 0; i < LOOP; i++) { key.data = &i; key.size = sizeof(i); record.size = key.size; record.data = key.data; st = ham_db_insert(db, 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_insert", st); } /* * now lookup all values * * for ham_db_find(), we could use the flag HAM_RECORD_USER_ALLOC, if WE * allocate record.data (otherwise the memory is automatically allocated * by hamsterdb) */ for (i = 0; i < LOOP; i++) { key.data = &i; key.size = sizeof(i); st = ham_db_find(db, 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_find", st); /* * check if the value is ok */ if (*(int *)record.data != i) { printf("ham_db_find() ok, but returned bad value\n"); return (-1); } } /* * close the database handle, then re-open it (to demonstrate how to open * an Environment and a Database) */ st = ham_db_close(db, 0); if (st != HAM_SUCCESS) error("ham_db_close", st); st = ham_env_close(env, 0); if (st != HAM_SUCCESS) error("ham_env_close", st); st = ham_env_open(&env, "test.db", 0, 0); if (st != HAM_SUCCESS) error("ham_env_open", st); st = ham_env_open_db(env, &db, DATABASE_NAME, 0, 0); if (st != HAM_SUCCESS) error("ham_env_open_db", st); /* now erase all values */ for (i = 0; i < LOOP; i++) { key.size = sizeof(i); key.data = &i; st = ham_db_erase(db, 0, &key, 0); if (st != HAM_SUCCESS) error("ham_db_erase", st); } /* * once more we try to find all values... every ham_db_find() call must * now fail with HAM_KEY_NOT_FOUND */ for (i = 0; i < LOOP; i++) { key.size = sizeof(i); key.data = &i; st = ham_db_find(db, 0, &key, &record, 0); if (st != HAM_KEY_NOT_FOUND) error("ham_db_find", st); } /* we're done! close the handles. HAM_AUTO_CLEANUP will also close the * 'db' handle */ st = ham_env_close(env, HAM_AUTO_CLEANUP); if (st != HAM_SUCCESS) error("ham_env_close", st); printf("success!\n"); return (0); }
int main(int argc, char **argv) { int i; ham_status_t st; /* status variable */ ham_db_t *db[MAX_DBS]; /* hamsterdb database objects */ ham_env_t *env; /* hamsterdb environment */ ham_cursor_t *cursor[MAX_DBS]; /* a cursor for each database */ ham_key_t key, cust_key, ord_key, c2o_key; ham_record_t record, cust_record, ord_record, c2o_record; customer_t customers[MAX_CUSTOMERS] = { { 1, "Alan Antonov Corp." }, { 2, "Barry Broke Inc." }, { 3, "Carl Caesar Lat." }, { 4, "Doris Dove Brd." } }; order_t orders[MAX_ORDERS] = { { 1, 1, "Joe" }, { 2, 1, "Tom" }, { 3, 3, "Joe" }, { 4, 4, "Tom" }, { 5, 3, "Ben" }, { 6, 3, "Ben" }, { 7, 4, "Chris" }, { 8, 1, "Ben" } }; memset(&key, 0, sizeof(key)); memset(&record, 0, sizeof(record)); memset(&cust_key, 0, sizeof(cust_key)); memset(&cust_record, 0, sizeof(cust_record)); memset(&ord_key, 0, sizeof(ord_key)); memset(&ord_record, 0, sizeof(ord_record)); memset(&c2o_key, 0, sizeof(c2o_key)); memset(&c2o_record, 0, sizeof(c2o_record)); /* Now create a new database file for the Environment */ st = ham_env_create(&env, "test.db", 0, 0664, 0); if (st != HAM_SUCCESS) error("ham_env_create", st); /* * Then create the two Databases in this Environment; each Database * has a name - the first is our "customer" Database, the second * is for the "orders"; the third manages our 1:n relation and * therefore needs to enable duplicate keys */ st = ham_env_create_db(env, &db[DBIDX_CUSTOMER], DBNAME_CUSTOMER, 0, 0); if (st != HAM_SUCCESS) error("ham_env_create_db(customer)", st); st = ham_env_create_db(env, &db[DBIDX_ORDER], DBNAME_ORDER, 0, 0); if (st != HAM_SUCCESS) error("ham_env_create_db(order)", st); st = ham_env_create_db(env, &db[DBIDX_C2O], DBNAME_C2O, HAM_ENABLE_DUPLICATES, 0); if (st != HAM_SUCCESS) error("ham_env_create_db(c2o)", st); /* Create a Cursor for each Database */ for (i = 0; i < MAX_DBS; i++) { st = ham_cursor_create(&cursor[i], db[i], 0, 0); if (st != HAM_SUCCESS) error("ham_cursor_create" , st); } /* * Insert the customers in the customer table * * INSERT INTO customers VALUES (1, "Alan Antonov Corp."); * INSERT INTO customers VALUES (2, "Barry Broke Inc."); * etc */ for (i = 0; i < MAX_CUSTOMERS; i++) { key.size = sizeof(int); key.data = &customers[i].id; record.size = sizeof(customer_t); record.data = &customers[i]; st = ham_db_insert(db[0], 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_insert (customer)", st); } /* * And now the orders in the second Database; contrary to env1, * we only store the assignee, not the whole structure * * INSERT INTO orders VALUES (1, "Joe"); * INSERT INTO orders VALUES (2, "Tom"); */ for (i = 0; i < MAX_ORDERS; i++) { key.size = sizeof(int); key.data = &orders[i].id; record.size = sizeof(orders[i].assignee); record.data = orders[i].assignee; st = ham_db_insert(db[1], 0, &key, &record, 0); if (st != HAM_SUCCESS) error("ham_db_insert (order)", st); } /* * And now the 1:n relationships; the flag HAM_DUPLICATE creates * a duplicate key, if the key already exists * * INSERT INTO c2o VALUES (1, 1); * INSERT INTO c2o VALUES (2, 1); * etc */ for (i = 0; i < MAX_ORDERS; i++) { key.size = sizeof(int); key.data = &orders[i].customer_id; record.size = sizeof(int); record.data = &orders[i].id; st = ham_db_insert(db[2], 0, &key, &record, HAM_DUPLICATE); if (st != HAM_SUCCESS) error("ham_db_insert(c2o)", st); } /* * Now start the query - we want to dump each customer with his * orders * * loop over the customer; for each customer, loop over the 1:n table * and pick those orders with the customer id. then load the order * and print it * * the outer loop is similar to: * SELECT * FROM customers WHERE 1; */ while (1) { customer_t *customer; st = ham_cursor_move(cursor[0], &cust_key, &cust_record, HAM_CURSOR_NEXT); if (st != HAM_SUCCESS) { /* reached end of the database? */ if (st == HAM_KEY_NOT_FOUND) break; else error("ham_cursor_next(customer)", st); } customer = (customer_t *)cust_record.data; /* print the customer id and name */ printf("customer %d ('%s')\n", customer->id, customer->name); /* * loop over the 1:n table * * before we start the loop, we move the cursor to the * first duplicate key * * SELECT * FROM customers, orders, c2o * WHERE c2o.customer_id=customers.id AND * c2o.order_id=orders.id; */ c2o_key.data = &customer->id; c2o_key.size = sizeof(int); st = ham_cursor_find(cursor[2], &c2o_key, 0, 0); if (st != HAM_SUCCESS) { if (st == HAM_KEY_NOT_FOUND) continue; error("ham_cursor_find(c2o)", st); } st = ham_cursor_move(cursor[2], 0, &c2o_record, 0); if (st != HAM_SUCCESS) error("ham_cursor_move(c2o)", st); do { int order_id; order_id = *(int *)c2o_record.data; ord_key.data = &order_id; ord_key.size = sizeof(int); /* * load the order * SELECT * FROM orders WHERE id = order_id; */ st = ham_db_find(db[1], 0, &ord_key, &ord_record, 0); if (st != HAM_SUCCESS) error("ham_db_find(order)", st); printf(" order: %d (assigned to %s)\n", order_id, (char *)ord_record.data); /* * The flag HAM_ONLY_DUPLICATES restricts the cursor * movement to the duplicate list. */ st = ham_cursor_move(cursor[2], &c2o_key, &c2o_record, HAM_CURSOR_NEXT|HAM_ONLY_DUPLICATES); if (st != HAM_SUCCESS) { /* reached end of the database? */ if (st == HAM_KEY_NOT_FOUND) break; else error("ham_cursor_next(c2o)", st); } } while (1); } /* * Now close the Environment handle; the flag * HAM_AUTO_CLEANUP will automatically close all Databases and * Cursors */ st = ham_env_close(env, HAM_AUTO_CLEANUP); if (st != HAM_SUCCESS) error("ham_env_close", st); printf("success!\n"); return (0); }
int main(int argc, char **argv) { ham_status_t st; /* status variable */ ham_env_t *env; /* hamsterdb environment object */ ham_db_t *db; /* hamsterdb database object */ ham_cursor_t *cursor; /* a database cursor */ char line[1024 * 4]; /* a buffer for reading lines */ ham_key_t key; ham_record_t record; memset(&key, 0, sizeof(key)); memset(&record, 0, sizeof(record)); printf("This sample uses hamsterdb to sort data.\n"); printf("Reading from stdin...\n"); /* * Create a new hamsterdb Environment. * We could create an In-Memory-Environment to speed up the sorting. */ st = ham_env_create(&env, "test.db", 0, 0664, 0); if (st != HAM_SUCCESS) { printf("ham_env_create() failed with error %d\n", st); return (-1); } st = ham_env_create_db(env, &db, DATABASE_NAME, HAM_ENABLE_EXTENDED_KEYS | HAM_ENABLE_DUPLICATES, 0); if (st != HAM_SUCCESS) { printf("ham_env_create_db() failed with error %d\n", st); return (-1); } /* * Since we use strings as our database keys we use our own comparison * function based on strcmp instead of the default memcmp function. */ st = ham_db_set_compare_func(db, my_string_compare); if (st) { printf("ham_set_compare_func() failed with error %d\n", st); return (-1); } /* * Now read each line from stdin and split it in words; then each * word is inserted into the database */ while (fgets(line, sizeof(line), stdin)) { char *start = line, *p; /* * strtok is not the best function because it's not threadsafe * and not flexible, but it's good enough for this example. */ while ((p = strtok(start, " \t\r\n"))) { key.data = p; key.size = (ham_size_t)strlen(p) + 1; /* also store the terminating * 0-byte */ st = ham_db_insert(db, 0, &key, &record, 0); if (st != HAM_SUCCESS && st!=HAM_DUPLICATE_KEY) { printf("ham_db_insert() failed with error %d\n", st); return (-1); } printf("."); start = 0; } } /* create a cursor */ st = ham_cursor_create(&cursor, db, 0, 0); if (st != HAM_SUCCESS) { printf("ham_cursor_create() failed with error %d\n", st); return (-1); } /* iterate over all items with HAM_CURSOR_NEXT, and print the words */ while (1) { st = ham_cursor_move(cursor, &key, &record, HAM_CURSOR_NEXT); if (st != HAM_SUCCESS) { /* reached end of the database? */ if (st == HAM_KEY_NOT_FOUND) break; else { printf("ham_cursor_next() failed with error %d\n", st); return (-1); } } /* print the word */ printf("%s\n", (const char *)key.data); } /* * Then close the handles; the flag HAM_AUTO_CLEANUP will automatically * close all database and cursors, and we do not need to call * ham_cursor_close and ham_db_close */ st = ham_env_close(env, HAM_AUTO_CLEANUP); if (st != HAM_SUCCESS) { printf("ham_env_close() failed with error %d\n", st); return (-1); } /* success! */ return (0); }