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
[email protected]
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users