SQLite Custom Data Types: Define and Use User-Defined Types
SQLite supports extending its built-in data types through extensions, allowing developers to define new data types tailored to specific requirements, such as dates, geographic locations, or enums. The core of custom data types lies in writing extension modules in C and registering them within SQLite as operable types.
Basic Steps for Defining Custom Data Types
- Write the Extension Module
First, create a C extension module containing functions to define the custom type. For example, define aDatetype with a structure comprising year, month, and day fields.// date.c #include <sqlite3.h> #include <stdio.h> typedef struct { int year; int month; int day; } Date; static int date_compare(const void *a, const void *b) { const Date *d1 = a; const Date *d2 = b; if (d1->year < d2->year) return -1; if (d1->year > d2->year) return 1; if (d1->month < d2->month) return -1; if (d1->month > d2->month) return 1; return d1->day - d2->day; } static int date_open(sqlite3 *db, const char *name, int flags, void **pppp) { *pppp = (void *)date; return SQLITE_OK; } static int date_close(sqlite3 *db, void *pppp) { return SQLITE_OK; } static int date_vdbopen(sqlite3 *db, const char *name, int flags, void **pppp) { *pppp = (void *)date; return SQLITE_OK; } static int date_vdbclose(sqlite3 *db, void *pppp) { return SQLITE_OK; } - Register the Type
Within the extension module, register the custom type into SQLite's type system. For example, register theDatetype using thesqlite3_create_functionfunction.sqlite3_create_function(db, "DATE", 1, SQLITE_UTF8, (sqlite3_api)date_open, (sqlite3_api)date_close, (sqlite3_api)date_vdbopen, (sqlite3_api)date_vdbclose); - Use Custom Types in the Database
When creating the database, utilize the custom type, for example:sqlite3_create_db("mydb", 10, "CREATE TABLE users (id INTEGER PRIMARY KEY, date DATE);");
Use Cases for Custom Data Types
Custom data types are suitable for scenarios requiring complex logic or interaction with external systems. Examples include:
- Date Types: Create date fields using the
DATEfunction, supporting sorting, comparison, and formatting. - Geographic Location Types: Define structures containing latitude and longitude to store geographic coordinates.
- Enum Types: Use the
ENUMfunction to define a limited range of values, such asSTATUS("active", "inactive").
Precautions
- Registration Order: Ensure that custom types are positioned correctly in SQLite's type registration table; otherwise, the type may not be recognized.
- Type Restrictions: Custom types cannot be directly used in query conditions (e.g.,
WHEREclauses) and must be converted to standard types via functions. - Performance Considerations: Custom types may increase memory overhead; balance performance requirements with functional needs.
Practical Application Example
Developers can implement more flexible data models using custom types. For instance, create a Location type to store latitude and longitude:
// location.c
typedef struct {
double lat;
double lon;
} Location;
static int location_compare(const void *a, const void *b) {
const Location *l1 = a;
const Location *l2 = b;
if (l1->lat < l2->lat) return -1;
if (l1->lat > l2->lat) return 1;
return l1->lon - l2->lon;
}
sqlite3_create_function(db, "LOCATION", 1, SQLITE_UTF8, (sqlite3_api)location_open, (sqlite3_api)location_close, (sqlite3_api)location_vdbopen, (sqlite3_api)location_vdbclose);
Through the steps outlined above, developers can flexibly extend SQLite's data type capabilities to meet complex data storage requirements.