On 6 Dec 2012, at 05:21, Dan Kennedy wrote: > It still seems likely that the collation returns the wrong result > some circumstances. Posting the code for it is probably the right > thing to do.
Thanks for the encouragement! I've used conditionally compiled sections so that the same code can be used to generate either an SQLite3 extension or a stand-alone executable for testing and demonstration. This demo compiles and runs under Ubuntu and OSX, and presents the sorted strings in the expected order. So far, I haven't tried to compile the extension under OSX. This and my Makefile follow below, as I understand attachments are not supported on this list. /Niall -- Makefile -- beware conversion of TABs -- # inlude for sqlite3 # replace by the directory that contains sqlite3ext.h INCLUDE = -I/usr/include ARCH = SOEXT = so CFLAGS = so_files = libsqliteipv6.$(SOEXT) all: $(so_files) .PHONY: extend demo clean sqlite3-ipv6-ext.o : sqlite3-ipv6-ext.c demo: ip-extension-demo ip-extension-demo: ip-extension.c $(CC) $< -o $@ -lsqlite3 extend: ip-extension.so ip-extension.so: CFLAGS=$(INCLUDE) -DEXTEND_SQLITE3 -fPIC -fno-stack-protector $(ARCH) ip-extension.so: ip-extension.o $(LD) -shared -o $@ $< clean : rm -f *.o a.out core core.* *% *~ *.$(SOEXT) -- ip-extension.c -- /* ** Parse an IP address, prefix, or range */ #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sqlite3.h> #ifdef EXTEND_SQLITE3 #include <sqlite3ext.h> SQLITE_EXTENSION_INIT1 #endif #define WO_DATA_SZ 256 struct work_object { size_t size; struct {size_t length; unsigned char *data;} string; struct {size_t length; unsigned char *data;} source; unsigned char wire[sizeof(struct in6_addr)]; unsigned char type; }; struct work_object* new_work_object() { struct work_object *this; unsigned char *p; p = sqlite3_malloc(WO_DATA_SZ + sizeof(struct work_object)); this = p; this->type = 255; this->size = WO_DATA_SZ; this->string.length = 0; this->string.data = p + sizeof(struct work_object); this->string.data[0] = '\0'; this->string.data[WO_DATA_SZ - 1] = '\0'; this->source.length = 0; this->source.data = NULL; return this; } struct work_object* prime_work_object(struct work_object *this, const int n, const void *source ) { struct work_object *p; size_t sz; p = this ? this : new_work_object(); p->source.data = source; p->source.length = n; p->type = 255; if (inet_pton(AF_INET6, p->source.data, p->wire) > 0) { p->type = 6; } else if (inet_pton(AF_INET, p->source.data, p->wire) > 0) { p->type = 4; } return p; } void stringify_work_object(struct work_object *this) { this->string.length = 0; this->string.data[0] = '\0'; this->string.data[WO_DATA_SZ - 1] = '\0'; if (this->type == 6) { inet_ntop(AF_INET6, this->wire, this->string.data, this->size - 1); this->string.length = strlen(this->string.data); } else if (this->type == 4) { inet_ntop(AF_INET, this->wire, this->string.data, this->size - 1); this->string.length = strlen(this->string.data); } } int compare_work_objects(struct work_object *this, struct work_object *that) { if (this->type != that->type) return this->type - that->type; if (this->type == 6) return memcmp(this->wire, that->wire, sizeof(struct in6_addr)); if (this->type == 4) return memcmp(this->wire, that->wire, sizeof(struct in_addr)); return strncmp(this->source.data, that->source.data, 1 + (this->source.length < that->source.length) ? this->source.length : that->source.length); } #ifdef EXTEND_SQLITE3 /* SQLite3 extension interface here */ int compare_ipaddrs (void *q, /* required by API: not used */ int na, const void *pa, /* a: length, string */ int nb, const void *pb /* b: length, string */ ) { struct work_object *a, *b; int v; a = prime_work_object(NULL, na, pa); b = prime_work_object(NULL, nb, pb); v = compare_work_objects(a, b); sqlite3_free(a); sqlite3_free(b); return v; } /* SQLite invokes this routine once when it loads the extension. ** Create new functions, collating sequences, and virtual table ** modules here. This is usually the only exported symbol in ** the shared library. */ int sqlite3_extension_init ( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { SQLITE_EXTENSION_INIT2(pApi) ; /* sqlite3_create_function(db, "displayip", 1, SQLITE_UTF8, 0, display1, 0, 0); */ sqlite3_create_collation( db, /* sqlite3* */ "ipaddress", /* const char *zName */ SQLITE_UTF8, /* int eTextRep */ NULL, /* void *pArg -- not used */ compare_ipaddrs /* int(*xCompare)(void*,int,const void*, int,const void*) */ ); return 0; } #else /* Standalone demonstration code here */ int compare_work_references(struct work_object **this, struct work_object **that) { return compare_work_objects(*this, *that); } void display_work_object(struct work_object *this) { int i; printf(" type: %hhu\n", this->type); printf(" size: %lu\n", this->size); if (this->source.data) { printf(" source data: (%lu) \"%s\"\n", this->source.length, this->source.data); } if (this->string.length) { printf(" string data: (%lu) \"%s\"\n", this->string.length, this->string.data); } if (this->type != 255) { printf(" wire: "); for (i=0; i<((this->type == 4) ? 4 : sizeof(this->wire)); i++) { printf("%02x", this->wire[i]); } printf("\n"); } } void usage() { printf("\n%s\n\n", " Usage: ip-extension-demo ip-address [...]"); } int main(int argc, char *argv[]) { if ( argc == 1 ) { usage(); exit(EXIT_FAILURE); } struct work_object **w, *p, *q; w = sqlite3_malloc((argc-1)*sizeof(void*)); int i, j, sz, wc; wc = argc - 1; for (i=0; i<wc; i++) { w[i] = prime_work_object(NULL, strlen(argv[i+1]), argv[i+1]); stringify_work_object(w[i]); } qsort(w, wc, sizeof(void *), compare_work_references); for (i=0; i<wc;) { p = w[i++]; q = (i==wc) ? NULL : w[i]; /* */ display_work_object(p); /* */ /* if ((q == NULL) || strncmp(p->data, q->data, (p->size > q->size) ? p->size : q->size)) */ printf("%s\n", ((p->string.length) ? p->string.data : p->source.data)); sqlite3_free(p); } sqlite3_free(w); exit(EXIT_SUCCESS); } #endif -- MD5 digests for protection against cut-n-paste errors -- 542f41580f766cf2b030b66a04ea17ba Makefile da2bbdb9a1c1160f0ffa54bc1d04414d ip-extension.c -- Ends -- _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users