File indexing completed on 2024-04-28 15:58:54

0001 /* This file is part of the KDE project
0002    Copyright (C) 2015 Jarosław Staniek <staniek@kde.org>
0003 
0004    Contains portions of sqlite3.c licensed under public domain. The author disclaims
0005    copyright to this source code.
0006 
0007    This program is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This program is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this program; see the file COPYING.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "SqliteFunctions.h"
0024 
0025 #include <QDebug>
0026 
0027 #include <cctype>
0028 
0029 /*
0030 ** Integers of known sizes.  These typedefs might change for architectures
0031 ** where the sizes very.  Preprocessor macros are available so that the
0032 ** types can be conveniently redefined at compile-type.  Like this:
0033 **
0034 **         cc '-DUINTPTR_TYPE=long long int' ...
0035 */
0036 #ifndef UINT32_TYPE
0037 # ifdef HAVE_UINT32_T
0038 #  define UINT32_TYPE uint32_t
0039 # else
0040 #  define UINT32_TYPE unsigned int
0041 # endif
0042 #endif
0043 #ifndef UINT16_TYPE
0044 # ifdef HAVE_UINT16_T
0045 #  define UINT16_TYPE uint16_t
0046 # else
0047 #  define UINT16_TYPE unsigned short int
0048 # endif
0049 #endif
0050 #ifndef INT16_TYPE
0051 # ifdef HAVE_INT16_T
0052 #  define INT16_TYPE int16_t
0053 # else
0054 #  define INT16_TYPE short int
0055 # endif
0056 #endif
0057 #ifndef UINT8_TYPE
0058 # ifdef HAVE_UINT8_T
0059 #  define UINT8_TYPE uint8_t
0060 # else
0061 #  define UINT8_TYPE unsigned char
0062 # endif
0063 #endif
0064 #ifndef INT8_TYPE
0065 # ifdef HAVE_INT8_T
0066 #  define INT8_TYPE int8_t
0067 # else
0068 #  define INT8_TYPE signed char
0069 # endif
0070 #endif
0071 #ifndef LONGDOUBLE_TYPE
0072 # define LONGDOUBLE_TYPE long double
0073 #endif
0074 typedef sqlite_int64 i64;          /* 8-byte signed integer */
0075 typedef sqlite_uint64 u64;         /* 8-byte unsigned integer */
0076 typedef UINT32_TYPE u32;           /* 4-byte unsigned integer */
0077 typedef UINT16_TYPE u16;           /* 2-byte unsigned integer */
0078 typedef INT16_TYPE i16;            /* 2-byte signed integer */
0079 typedef UINT8_TYPE u8;             /* 1-byte unsigned integer */
0080 typedef INT8_TYPE i8;              /* 1-byte signed integer */
0081 
0082 static bool tryExec(sqlite3 *db, const char *sql)
0083 {
0084     return SQLITE_OK == sqlite3_exec(db, sql, nullptr /*callback*/,
0085                                      nullptr /* 1st argument to callback */, nullptr /*err*/);
0086 }
0087 
0088 // BEGIN from sqlite3.c
0089 #define sqlite3Toupper(x)   toupper((unsigned char)(x))
0090 #define sqlite3Isalpha(x)   isalpha((unsigned char)(x))
0091 
0092 /*
0093 ** Compute the soundex encoding of a word.
0094 **
0095 ** IMP: R-59782-00072 The soundex(X) function returns a string that is the
0096 ** soundex encoding of the string X.
0097 */
0098 static void soundexFunc(
0099   sqlite3_context *context,
0100   int argc,
0101   sqlite3_value **argv
0102 ){
0103   char zResult[8];
0104   const u8 *zIn;
0105   int i, j;
0106   static const unsigned char iCode[] = {
0107     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0108     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0109     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0110     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0111     0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
0112     1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0113     0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
0114     1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0115   };
0116   assert( argc==1 );
0117   zIn = (u8*)sqlite3_value_text(argv[0]);
0118   if( zIn==0 ) zIn = (u8*)"";
0119   for(i=0; zIn[i] && !sqlite3Isalpha(zIn[i]); i++){}
0120   if( zIn[i] ){
0121     u8 prevcode = iCode[zIn[i]&0x7f];
0122     zResult[0] = sqlite3Toupper(zIn[i]);
0123     for(j=1; j<4 && zIn[i]; i++){
0124       int code = iCode[zIn[i]&0x7f];
0125       if( code>0 ){
0126         if( code!=prevcode ){
0127           prevcode = code;
0128           zResult[j++] = code + '0';
0129         }
0130       }else{
0131         prevcode = 0;
0132       }
0133     }
0134     while( j<4 ){
0135       zResult[j++] = '0';
0136     }
0137     zResult[j] = 0;
0138     sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT);
0139   }else{
0140     /* IMP: R-64894-50321 The string "?000" is returned if the argument
0141     ** is NULL or contains no ASCII alphabetic characters. */
0142     sqlite3_result_text(context, "?000", 4, SQLITE_STATIC);
0143   }
0144 }
0145 
0146 bool createCustomSQLiteFunctions(sqlite3 *db)
0147 {
0148     int eTextRep = SQLITE_UTF8;
0149 #if SQLITE_VERSION_NUMBER >= 3008003
0150     eTextRep |= SQLITE_DETERMINISTIC;
0151 #endif
0152     if (!tryExec(db, "SELECT SOUNDEX()")) {
0153         int res = sqlite3_create_function_v2(
0154             db,
0155             "SOUNDEX",
0156             1, //nArg
0157             eTextRep,
0158             nullptr, // pApp
0159             soundexFunc,
0160             nullptr, // xStep
0161             nullptr, // xFinal
0162             nullptr // xDestroy
0163         );
0164         if (res != SQLITE_OK) {
0165             return false;
0166         }
0167     }
0168     return true;
0169 }
0170 
0171 // END from sqlite3.c