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

Reply via email to