xref: /sqlite-3.40.0/ext/misc/uint.c (revision 3d42fb78)
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