{"id":22472787,"url":"https://github.com/zoff99/csorma","last_synced_at":"2026-04-15T23:31:32.883Z","repository":{"id":237388897,"uuid":"794431527","full_name":"zoff99/csorma","owner":"zoff99","description":"C Simple ORM (Android?) - written in pure C","archived":false,"fork":false,"pushed_at":"2026-03-24T08:48:20.000Z","size":11532,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-25T10:45:39.748Z","etag":null,"topics":["c","orm","sqlcipher","sqlite","threadsafe"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zoff99.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://liberapay.com/zoff/donate","https://blockstream.info/address/1TRifA7eNLHZEcCTj43eYVWHBbLqTuXkS","https://buy.stripe.com/6oE00FbLieDMc7ecMN"]}},"created_at":"2024-05-01T06:26:12.000Z","updated_at":"2026-03-24T08:48:06.000Z","dependencies_parsed_at":"2024-05-30T13:34:34.603Z","dependency_job_id":"fe0ce5bf-5522-4060-be7d-f8a3663938d0","html_url":"https://github.com/zoff99/csorma","commit_stats":null,"previous_names":["zoff99/csorma"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/zoff99/csorma","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoff99%2Fcsorma","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoff99%2Fcsorma/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoff99%2Fcsorma/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoff99%2Fcsorma/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zoff99","download_url":"https://codeload.github.com/zoff99/csorma/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoff99%2Fcsorma/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31864955,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"ssl_error","status_checked_at":"2026-04-15T15:24:39.138Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","orm","sqlcipher","sqlite","threadsafe"],"created_at":"2024-12-06T12:17:21.281Z","updated_at":"2026-04-15T23:31:32.858Z","avatar_url":"https://github.com/zoff99.png","language":"C","funding_links":["https://liberapay.com/zoff/donate","https://blockstream.info/address/1TRifA7eNLHZEcCTj43eYVWHBbLqTuXkS","https://buy.stripe.com/6oE00FbLieDMc7ecMN"],"categories":[],"sub_categories":[],"readme":"# C Simple ORM (Android?)\n\n[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html)\n[![Liberapay](https://img.shields.io/liberapay/goal/zoff.svg?logo=liberapay)](https://liberapay.com/zoff/donate)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/zoff99/csorma)\n\n### Oh nooo, Why?\nI was looking around for something very simple and easy to use in pure C and there was nothing around like that.\n\u003cbr\u003e\nIt is based on the wonderful Android-Orma by FUJI Goro\n\u003cbr\u003e\nand on my (not so wonderful) sorma\u003csup\u003e2\u003c/sup\u003e\n\u003cbr\u003e\nhttps://github.com/maskarade/Android-Orma\n\u003cbr\u003e\nhttps://github.com/gfx\n\u003cbr\u003e\nhttps://github.com/zoff99/sorma2\n\n\u003cimg src=\"https://raw.githubusercontent.com/zoff99/csorma/refs/heads/master/csorma_coms.png\" width=\"300\"\u003e\n\n\n### Features\n* pure C\n* Thread safe\n* safe Strings (UTF-8 or even broken UTF-8 or just random bytes)\n* easy to use (for most common SQL operations)\n* no dependencies (other than SQLite3 amalgamtion source file)\n* schema update management\n* works with ASAN\n* works with TSAN\n* works with UBSAN\n* \u003cb\u003esqlcipher\u003c/b\u003e encryption option (you need to have openssl (libssl and libcrypto) installed)\n\n### What is does NOT do\n* NOT optimized for speed\n* NOT optimized for small memory footprint\n* NO complex DB operations like JOIN or UNION etc.\n* NO multi column primary keys\n* NO non ASCII characters in table and column names\n* table and column names MUST NOT start or end with a `_` or a `number`\n* table and column names MUST only contain `[a-z][_]` (NO uppercase)\n* if table or column name starts with (or contains) `public` or `static` there could be issues\u003csup\u003e*\u003c/sup\u003e\n\n\u003csup\u003e*\u003c/sup\u003e\u003csup\u003e\u003csub\u003e\u003cI\u003etry to avoid SQL reserved words in table and column names, there may also be some other naming conflicts.\u003c/I\u003e\u003c/sub\u003e\u003c/sup\u003e\n\n### Supported architechtures\n* Linux\n* Raspi\n* Windows\n* macOS\n* macOS silicon arm64\n* s390\n* mips\n* riscV\n\n### Usage\n#### Create your first C project with csorma\ncreate a directory for your project:\n```bash\nmkdir -p ./mysuperstuff/\n```\n\ncreate one file for each database table that you need.\n\u003cbr\u003e\ncreate file for db table `Person` as `./mysuperstuff/_csorma_Person.java`\n\u003cbr\u003e(don't worry it is not really Java, we just use the syntax here)\n```Java\n@Table\npublic class Person\n{\n    @PrimaryKey(autoincrement = true)\n    public long id;\n    @Column\n    public String name;\n    @Column\n    public String address;\n    @Column\n    public int social_number;\n}\n```\n\nnow create the C sources with the Java CSORMA Generator. \u003cb\u003eyou need at least java 17\u003c/b\u003e.\u003cbr\u003e\n```bash\njavac csorma_generator.java \u0026\u0026 java csorma_generator ./mysuperstuff/\n```\n\nyour project is now ready to start.\u003cbr\u003e\nenter the project directory:\n```bash\ncd ./mysuperstuff/gen/\n```\n\nnow build your C project stub and run it:\n```bash\nmake csorma_stub\n./csorma_stub\n```\n\nif you want to build your project with \u003cb\u003esqlcipher\u003c/b\u003e (you need to have openssl and libssl and libcrypto installed):\n```bash\nmake clean # clean from the previous build\nENCRYPT_CS=1 make csorma_stub\n./csorma_stub\n```\n\nthe output should look (something) like this:\n```\nSTUB: CSORMA version: 0.99.3-SQLCIPHER\nSTUB: CSORMA SQLite version: 3.46.1\nSTUB: CSORMA sqlcipher version: 4.6.1 community\nSTUB: setting sqlcipher key. result = 0\nSTUB: disabling WAL mode. result = 0\nSTUB: schema upgrade from 0 to 1\nSTUB: creating table: Person\nSTUB: res1: 0\n\nSTUB: all OK\n\n```\n\nyou now have your working C project stub.\u003cbr\u003e\n\n#### Add some more SQL stuff to your new project\n\nopen your C project stub in your favorite C Code Editor or IDE:\n```\nvim csorma_stub.c\n```\n\nnow let's add commands\u003cbr\u003e\n(between the `------- your commands here -------` lines)\u003cbr\u003e\nto insert a row:\n```C\n{ // HINT: using blocks here to have `p` be a local var\nPerson *p = orma_new_Person(o-\u003edb);\np-\u003ename = csb(\"Larry Wilson\");\np-\u003eaddress = csb(\"1 Larry Drive, Sunset Town\");\np-\u003esocial_number = 381739;\nint64_t inserted_id = orma_insertIntoPerson(p);\norma_free_Person(p);\nprintf(\"STUB: inserted id: %lld\\n\", (long long)inserted_id);\n} // HINT: using blocks here to have `p` be a local var\n```\n\nnow lets count how many Persons have the social number `381739`:\n```C\n{\nPerson *p = orma_selectFromPerson(o-\u003edb);\nprintf(\"STUB: count: %d\\n\", (int)p-\u003esocial_numberEq(p, 381739)-\u003ecount(p));\n}\n```\n\nnow we do the same but use the `less than` operator `Lt()`\n```C\n{\nPerson *p = orma_selectFromPerson(o-\u003edb);\nprintf(\"STUB: count: %d\\n\", (int)p-\u003esocial_numberLt(p, 400000)-\u003ecount(p));\n}\n```\n\nand insert another Person:\n```C\n{\nPerson *p = orma_new_Person(o-\u003edb);\np-\u003ename = csb(\"Martha Liebowitz\");\np-\u003eaddress = csb(\"2035 Morning Road, Big City\");\np-\u003esocial_number = 139807;\nint64_t inserted_id = orma_insertIntoPerson(p);\norma_free_Person(p);\nprintf(\"STUB: inserted id: %lld\\n\", (long long)inserted_id);\n}\n```\n\nlets iterate through the result of a select statement:\n```C\n{\nPerson *p = orma_selectFromPerson(o-\u003edb);\nPersonList *pl = p-\u003etoList(p);\nprintf(\"STUB: pl-\u003eitems=%lld\\n\", (long long)pl-\u003eitems);\nPerson **pd = pl-\u003el;\nfor(int i=0;i\u003cpl-\u003eitems;i++)\n{\n    printf(\"STUB: id=%ld\\n\", (*pd)-\u003eid);\n    printf(\"STUB: name=\\\"%s\\\"\\n\", (*pd)-\u003ename-\u003es);\n    printf(\"STUB: address=\\\"%s\\\"\\n\", (*pd)-\u003eaddress-\u003es);\n    printf(\"STUB: social_number=\\\"%d\\\"\\n\", (*pd)-\u003esocial_number);\n    pd++;\n}\norma_free_PersonList(pl);\n}\n```\n\nhere we update all addresses:\n```C\n{\nPerson *p = orma_updatePerson(o-\u003edb);\nint64_t affected_rows3 = p-\u003eaddressSet(p, csb(\"1337 Funky Lane, Lala Land\"))-\u003eexecute(p);\nprintf(\"STUB: affected rows: %d\\n\", (int)affected_rows3);\n}\n```\n\nif we do the iteration from above again we will see the changed data\u003cbr\u003e\nit will look something like that:\n```\nSTUB: affected rows: 2\nSTUB: pl-\u003eitems=2\nSTUB: id=1\nSTUB: name=\"Larry Wilson\"\nSTUB: address=\"1337 Funky Lane, Lala Land\"\nSTUB: social_number=\"381739\"\nSTUB: id=2\nSTUB: name=\"Martha Liebowitz\"\nSTUB: address=\"1337 Funky Lane, Lala Land\"\nSTUB: social_number=\"139807\"\n```\n\ndelete specifc rows:\n```C\n{\nPerson *p = orma_deleteFromPerson(o-\u003edb);\nint64_t affected_rows2 = p-\u003esocial_numberEq(p, 139807)-\u003e\n    nameEq(p, csb(\"Martha Liebowitz\"))-\u003eexecute(p);\nprintf(\"STUB: affected rows: %d\\n\", (int)affected_rows2);\n}\n```\n\nin the end run a freehand SQL to drop the table:\n```C\n{\nchar *sql3 = \"DROP TABLE Person;\";\nCSORMA_GENERIC_RESULT res3 = OrmaDatabase_run_multi_sql(o, (const uint8_t *)sql3);\nprintf(\"STUB: res3: %d\\n\", res3);\n}\n```\n\n#### Stub C code, some functions explained\n\nhelper function csb and csc:\u003cbr\u003e\ncsb() will build a `csorma_str*` from a `const char*` NULL terminated C string\u003cbr\u003e\nand csc() will append (or create) a `csorma_str*` from a `buffer and length` (no need for NULL termination)\n```C\n#define csb(buf)\n#define csc(buf,len)\n```\n\ninclude the header file:\n```C\n#include \"csorma_runtime.h\"\n```\n\ninitialize the database:\n```C\nconst char *db_dir = \"./\";\nconst char *db_filename = \"stub.db\";\nOrmaDatabase *o = OrmaDatabase_init(\n    (uint8_t*)db_dir, strlen(db_dir),\n    (uint8_t*)db_filename, strlen(db_filename)\n);\n```\n\ninitialize an encrypted database (if csorma was compiled with encryption support):\n```C\nconst char *db_dir = \"./\";\nconst char *db_filename = \"stub.db\";\nOrmaDatabase *o = OrmaDatabase_init(\n    (uint8_t*)db_dir, strlen(db_dir),\n    (uint8_t*)db_filename, strlen(db_filename)\n);\n\nconst char *key = \"passphrase123!\";\nint result_setkey = OrmaDatabase_key(o, (uint8_t*)key, strlen(key));\nprintf(\"setting sqlcipher key. result = %d\\n\", result_setkey);\n\n// HINT: set WAL mode\nCSORMA_GENERIC_RESULT result_setwal = OrmaDatabase_set_wal_mode(o, true);\nprintf(\"enabling WAL mode. result = %d\\n\", (int)result_setwal);\n```\n\nyou can also initialize an in-memory database:\n```C\nconst char *db_dir = \":memory:\";\nconst char *db_filename = \"\";\nOrmaDatabase *o = OrmaDatabase_init(\n    (uint8_t*)db_dir, strlen(db_dir),\n    (uint8_t*)db_filename, strlen(db_filename)\n);\n```\n\nrun a freehand SQL:\n```C\nchar *sql1 = \"CREATE TABLE IF NOT EXISTS Message (\"\n        \"message_id\tINTEGER NOT NULL,\"\n        \"read\tBOOLEAN,\"\n        \"direction\tINTEGER ,\"\n        \"text\tTEXT,\"\n        \"id\tINTEGER,\"\n        \"PRIMARY KEY(\\\"id\\\" AUTOINCREMENT)\"\n        \");\"\n        \"insert into message(message_id,text) values('123','test message');\";\nCSORMA_GENERIC_RESULT res1 = OrmaDatabase_run_multi_sql(o, sql1);\n```\n\nshutdown the database:\n```C\nOrmaDatabase_shutdown(o);\n```\n\n### sqlcipher source code\nsqlcipher source code is generated from latest [sqlcipher git repository](https://github.com/sqlcipher/sqlcipher) using this [tool](https://github.com/zoff99/gen_sqlcipher_amalgamation)\u003cbr\u003e\nyou can download the generated sqlcipher code from https://github.com/zoff99/gen_sqlcipher_amalgamation/releases/tag/nightly\n\n### Automated Screenshots taken from CI\n\u003cimg src=\"https://github.com/zoff99/csorma/releases/download/nightly/console_01_screen-0.png\" width=\"300\"\u003e\n\u003cbr\u003e\n\n\u003cbr\u003e\nAny use of this project's code by GitHub Copilot, past or present, is done\nwithout our permission.  We do not consent to GitHub's use of this project's\ncode in Copilot.\n\u003cbr\u003e\nNo part of this work may be used or reproduced in any manner for the purpose of training artificial intelligence technologies or systems.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoff99%2Fcsorma","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzoff99%2Fcsorma","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoff99%2Fcsorma/lists"}