1e6a85962Sdrh /*
2e6a85962Sdrh ** 2020-04-14
3e6a85962Sdrh **
4e6a85962Sdrh ** The author disclaims copyright to this source code. In place of
5e6a85962Sdrh ** a legal notice, here is a blessing:
6e6a85962Sdrh **
7e6a85962Sdrh ** May you do good and not evil.
8e6a85962Sdrh ** May you find forgiveness for yourself and forgive others.
9e6a85962Sdrh ** May you share freely, never taking more than you give.
10e6a85962Sdrh **
11e6a85962Sdrh ******************************************************************************
12e6a85962Sdrh **
13e6a85962Sdrh ** This SQLite extension implements the UINT collating sequence.
14e6a85962Sdrh **
15e6a85962Sdrh ** UINT works like BINARY for text, except that embedded strings
16e6a85962Sdrh ** of digits compare in numeric order.
17e6a85962Sdrh **
18e6a85962Sdrh ** * Leading zeros are handled properly, in the sense that
19e6a85962Sdrh ** they do not mess of the maginitude comparison of embedded
20e6a85962Sdrh ** strings of digits. "x00123y" is equal to "x123y".
21e6a85962Sdrh **
22e6a85962Sdrh ** * Only unsigned integers are recognized. Plus and minus
23e6a85962Sdrh ** signs are ignored. Decimal points and exponential notation
24e6a85962Sdrh ** are ignored.
25e6a85962Sdrh **
26e6a85962Sdrh ** * Embedded integers can be of arbitrary length. Comparison
27e6a85962Sdrh ** is *not* limited integers that can be expressed as a
28e6a85962Sdrh ** 64-bit machine integer.
29e6a85962Sdrh */
30e6a85962Sdrh #include "sqlite3ext.h"
31e6a85962Sdrh SQLITE_EXTENSION_INIT1
32e6a85962Sdrh #include <assert.h>
33e6a85962Sdrh #include <string.h>
34e6a85962Sdrh #include <ctype.h>
35e6a85962Sdrh
36e6a85962Sdrh /*
37e6a85962Sdrh ** Compare text in lexicographic order, except strings of digits
38e6a85962Sdrh ** compare in numeric order.
39e6a85962Sdrh */
uintCollFunc(void * notUsed,int nKey1,const void * pKey1,int nKey2,const void * pKey2)40e6a85962Sdrh static int uintCollFunc(
41e6a85962Sdrh void *notUsed,
42e6a85962Sdrh int nKey1, const void *pKey1,
43e6a85962Sdrh int nKey2, const void *pKey2
44e6a85962Sdrh ){
45e6a85962Sdrh const unsigned char *zA = (const unsigned char*)pKey1;
46e6a85962Sdrh const unsigned char *zB = (const unsigned char*)pKey2;
47e6a85962Sdrh int i=0, j=0, x;
48*3d42fb78Sdrh (void)notUsed;
49e6a85962Sdrh while( i<nKey1 && j<nKey2 ){
50e6a85962Sdrh x = zA[i] - zB[j];
51e6a85962Sdrh if( isdigit(zA[i]) ){
52e6a85962Sdrh int k;
53e6a85962Sdrh if( !isdigit(zB[j]) ) return x;
54e6a85962Sdrh while( i<nKey1 && zA[i]=='0' ){ i++; }
55e6a85962Sdrh while( j<nKey2 && zB[j]=='0' ){ j++; }
56e6a85962Sdrh k = 0;
57e6a85962Sdrh while( i+k<nKey1 && isdigit(zA[i+k])
58e6a85962Sdrh && j+k<nKey2 && isdigit(zB[j+k]) ){
59e6a85962Sdrh k++;
60e6a85962Sdrh }
61e6a85962Sdrh if( i+k<nKey1 && isdigit(zA[i+k]) ){
62e6a85962Sdrh return +1;
63e6a85962Sdrh }else if( j+k<nKey2 && isdigit(zB[j+k]) ){
64e6a85962Sdrh return -1;
65e6a85962Sdrh }else{
66e6a85962Sdrh x = memcmp(zA+i, zB+j, k);
67e6a85962Sdrh if( x ) return x;
68e6a85962Sdrh i += k;
69e6a85962Sdrh j += k;
70e6a85962Sdrh }
71e6a85962Sdrh }else if( x ){
72e6a85962Sdrh return x;
73e6a85962Sdrh }else{
74e6a85962Sdrh i++;
75e6a85962Sdrh j++;
76e6a85962Sdrh }
77e6a85962Sdrh }
78e6a85962Sdrh return (nKey1 - i) - (nKey2 - j);
79e6a85962Sdrh }
80e6a85962Sdrh
81e6a85962Sdrh #ifdef _WIN32
82e6a85962Sdrh __declspec(dllexport)
83e6a85962Sdrh #endif
sqlite3_uint_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)84e6a85962Sdrh int sqlite3_uint_init(
85e6a85962Sdrh sqlite3 *db,
86e6a85962Sdrh char **pzErrMsg,
87e6a85962Sdrh const sqlite3_api_routines *pApi
88e6a85962Sdrh ){
89e6a85962Sdrh SQLITE_EXTENSION_INIT2(pApi);
90e6a85962Sdrh (void)pzErrMsg; /* Unused parameter */
91e6a85962Sdrh return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc);
92e6a85962Sdrh }
93