Annotation of embedaddon/php/ext/sqlite/libsqlite/src/func.c, revision 1.1.1.1
1.1 misho 1: /*
2: ** 2002 February 23
3: **
4: ** The author disclaims copyright to this source code. In place of
5: ** a legal notice, here is a blessing:
6: **
7: ** May you do good and not evil.
8: ** May you find forgiveness for yourself and forgive others.
9: ** May you share freely, never taking more than you give.
10: **
11: *************************************************************************
12: ** This file contains the C functions that implement various SQL
13: ** functions of SQLite.
14: **
15: ** There is only one exported symbol in this file - the function
16: ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
17: ** All other code has file scope.
18: **
19: ** $Id: func.c 195361 2005-09-07 15:11:33Z iliaa $
20: */
21: #include <ctype.h>
22: #include <math.h>
23: #include <stdlib.h>
24: #include <assert.h>
25: #include "sqliteInt.h"
26: #include "os.h"
27:
28: /*
29: ** Implementation of the non-aggregate min() and max() functions
30: */
31: static void minmaxFunc(sqlite_func *context, int argc, const char **argv){
32: const char *zBest;
33: int i;
34: int (*xCompare)(const char*, const char*);
35: int mask; /* 0 for min() or 0xffffffff for max() */
36:
37: if( argc==0 ) return;
38: mask = (int)sqlite_user_data(context);
39: zBest = argv[0];
40: if( zBest==0 ) return;
41: if( argv[1][0]=='n' ){
42: xCompare = sqliteCompare;
43: }else{
44: xCompare = strcmp;
45: }
46: for(i=2; i<argc; i+=2){
47: if( argv[i]==0 ) return;
48: if( (xCompare(argv[i], zBest)^mask)<0 ){
49: zBest = argv[i];
50: }
51: }
52: sqlite_set_result_string(context, zBest, -1);
53: }
54:
55: /*
56: ** Return the type of the argument.
57: */
58: static void typeofFunc(sqlite_func *context, int argc, const char **argv){
59: assert( argc==2 );
60: sqlite_set_result_string(context, argv[1], -1);
61: }
62:
63: /*
64: ** Implementation of the length() function
65: */
66: static void lengthFunc(sqlite_func *context, int argc, const char **argv){
67: const char *z;
68: int len;
69:
70: assert( argc==1 );
71: z = argv[0];
72: if( z==0 ) return;
73: #ifdef SQLITE_UTF8
74: for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
75: #else
76: len = strlen(z);
77: #endif
78: sqlite_set_result_int(context, len);
79: }
80:
81: /*
82: ** Implementation of the abs() function
83: */
84: static void absFunc(sqlite_func *context, int argc, const char **argv){
85: const char *z;
86: assert( argc==1 );
87: z = argv[0];
88: if( z==0 ) return;
89: if( z[0]=='-' && isdigit(z[1]) ) z++;
90: sqlite_set_result_string(context, z, -1);
91: }
92:
93: /*
94: ** Implementation of the substr() function
95: */
96: static void substrFunc(sqlite_func *context, int argc, const char **argv){
97: const char *z;
98: #ifdef SQLITE_UTF8
99: const char *z2;
100: int i;
101: #endif
102: int p1, p2, len;
103: assert( argc==3 );
104: z = argv[0];
105: if( z==0 ) return;
106: p1 = atoi(argv[1]?argv[1]:0);
107: p2 = atoi(argv[2]?argv[2]:0);
108: #ifdef SQLITE_UTF8
109: for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z2)!=0x80 ) len++; }
110: #else
111: len = strlen(z);
112: #endif
113: if( p1<0 ){
114: p1 += len;
115: if( p1<0 ){
116: p2 += p1;
117: p1 = 0;
118: }
119: }else if( p1>0 ){
120: p1--;
121: }
122: if( p1+p2>len ){
123: p2 = len-p1;
124: }
125: #ifdef SQLITE_UTF8
126: for(i=0; i<p1 && z[i]; i++){
127: if( (z[i]&0xc0)==0x80 ) p1++;
128: }
129: while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p1++; }
130: for(; i<p1+p2 && z[i]; i++){
131: if( (z[i]&0xc0)==0x80 ) p2++;
132: }
133: while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
134: #endif
135: if( p2<0 ) p2 = 0;
136: sqlite_set_result_string(context, &z[p1], p2);
137: }
138:
139: /*
140: ** Implementation of the round() function
141: */
142: static void roundFunc(sqlite_func *context, int argc, const char **argv){
143: int n;
144: double r;
145: char zBuf[100];
146: assert( argc==1 || argc==2 );
147: if( argv[0]==0 || (argc==2 && argv[1]==0) ) return;
148: n = argc==2 ? atoi(argv[1]) : 0;
149: if( n>30 ) n = 30;
150: if( n<0 ) n = 0;
151: r = sqliteAtoF(argv[0], 0);
152: sprintf(zBuf,"%.*f",n,r);
153: sqlite_set_result_string(context, zBuf, -1);
154: }
155:
156: /*
157: ** Implementation of the upper() and lower() SQL functions.
158: */
159: static void upperFunc(sqlite_func *context, int argc, const char **argv){
160: unsigned char *z;
161: int i;
162: if( argc<1 || argv[0]==0 ) return;
163: z = (unsigned char*)sqlite_set_result_string(context, argv[0], -1);
164: if( z==0 ) return;
165: for(i=0; z[i]; i++){
166: if( islower(z[i]) ) z[i] = toupper(z[i]);
167: }
168: }
169: static void lowerFunc(sqlite_func *context, int argc, const char **argv){
170: unsigned char *z;
171: int i;
172: if( argc<1 || argv[0]==0 ) return;
173: z = (unsigned char*)sqlite_set_result_string(context, argv[0], -1);
174: if( z==0 ) return;
175: for(i=0; z[i]; i++){
176: if( isupper(z[i]) ) z[i] = tolower(z[i]);
177: }
178: }
179:
180: /*
181: ** Implementation of the IFNULL(), NVL(), and COALESCE() functions.
182: ** All three do the same thing. They return the first non-NULL
183: ** argument.
184: */
185: static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
186: int i;
187: for(i=0; i<argc; i++){
188: if( argv[i] ){
189: sqlite_set_result_string(context, argv[i], -1);
190: break;
191: }
192: }
193: }
194:
195: /*
196: ** Implementation of random(). Return a random integer.
197: */
198: static void randomFunc(sqlite_func *context, int argc, const char **argv){
199: int r;
200: sqliteRandomness(sizeof(r), &r);
201: sqlite_set_result_int(context, r);
202: }
203:
204: /*
205: ** Implementation of the last_insert_rowid() SQL function. The return
206: ** value is the same as the sqlite_last_insert_rowid() API function.
207: */
208: static void last_insert_rowid(sqlite_func *context, int arg, const char **argv){
209: sqlite *db = sqlite_user_data(context);
210: sqlite_set_result_int(context, sqlite_last_insert_rowid(db));
211: }
212:
213: /*
214: ** Implementation of the change_count() SQL function. The return
215: ** value is the same as the sqlite_changes() API function.
216: */
217: static void change_count(sqlite_func *context, int arg, const char **argv){
218: sqlite *db = sqlite_user_data(context);
219: sqlite_set_result_int(context, sqlite_changes(db));
220: }
221:
222: /*
223: ** Implementation of the last_statement_change_count() SQL function. The
224: ** return value is the same as the sqlite_last_statement_changes() API function.
225: */
226: static void last_statement_change_count(sqlite_func *context, int arg,
227: const char **argv){
228: sqlite *db = sqlite_user_data(context);
229: sqlite_set_result_int(context, sqlite_last_statement_changes(db));
230: }
231:
232: /*
233: ** Implementation of the like() SQL function. This function implements
234: ** the build-in LIKE operator. The first argument to the function is the
235: ** string and the second argument is the pattern. So, the SQL statements:
236: **
237: ** A LIKE B
238: **
239: ** is implemented as like(A,B).
240: */
241: static void likeFunc(sqlite_func *context, int arg, const char **argv){
242: if( argv[0]==0 || argv[1]==0 ) return;
243: sqlite_set_result_int(context,
244: sqliteLikeCompare((const unsigned char*)argv[0],
245: (const unsigned char*)argv[1]));
246: }
247:
248: /*
249: ** Implementation of the glob() SQL function. This function implements
250: ** the build-in GLOB operator. The first argument to the function is the
251: ** string and the second argument is the pattern. So, the SQL statements:
252: **
253: ** A GLOB B
254: **
255: ** is implemented as glob(A,B).
256: */
257: static void globFunc(sqlite_func *context, int arg, const char **argv){
258: if( argv[0]==0 || argv[1]==0 ) return;
259: sqlite_set_result_int(context,
260: sqliteGlobCompare((const unsigned char*)argv[0],
261: (const unsigned char*)argv[1]));
262: }
263:
264: /*
265: ** Implementation of the NULLIF(x,y) function. The result is the first
266: ** argument if the arguments are different. The result is NULL if the
267: ** arguments are equal to each other.
268: */
269: static void nullifFunc(sqlite_func *context, int argc, const char **argv){
270: if( argv[0]!=0 && sqliteCompare(argv[0],argv[1])!=0 ){
271: sqlite_set_result_string(context, argv[0], -1);
272: }
273: }
274:
275: /*
276: ** Implementation of the VERSION(*) function. The result is the version
277: ** of the SQLite library that is running.
278: */
279: static void versionFunc(sqlite_func *context, int argc, const char **argv){
280: sqlite_set_result_string(context, sqlite_version, -1);
281: }
282:
283: /*
284: ** EXPERIMENTAL - This is not an official function. The interface may
285: ** change. This function may disappear. Do not write code that depends
286: ** on this function.
287: **
288: ** Implementation of the QUOTE() function. This function takes a single
289: ** argument. If the argument is numeric, the return value is the same as
290: ** the argument. If the argument is NULL, the return value is the string
291: ** "NULL". Otherwise, the argument is enclosed in single quotes with
292: ** single-quote escapes.
293: */
294: static void quoteFunc(sqlite_func *context, int argc, const char **argv){
295: if( argc<1 ) return;
296: if( argv[0]==0 ){
297: sqlite_set_result_string(context, "NULL", 4);
298: }else if( sqliteIsNumber(argv[0]) ){
299: sqlite_set_result_string(context, argv[0], -1);
300: }else{
301: int i,j,n;
302: char *z;
303: for(i=n=0; argv[0][i]; i++){ if( argv[0][i]=='\'' ) n++; }
304: z = sqliteMalloc( i+n+3 );
305: if( z==0 ) return;
306: z[0] = '\'';
307: for(i=0, j=1; argv[0][i]; i++){
308: z[j++] = argv[0][i];
309: if( argv[0][i]=='\'' ){
310: z[j++] = '\'';
311: }
312: }
313: z[j++] = '\'';
314: z[j] = 0;
315: sqlite_set_result_string(context, z, j);
316: sqliteFree(z);
317: }
318: }
319:
320: #ifdef SQLITE_SOUNDEX
321: /*
322: ** Compute the soundex encoding of a word.
323: */
324: static void soundexFunc(sqlite_func *context, int argc, const char **argv){
325: char zResult[8];
326: const char *zIn;
327: int i, j;
328: static const unsigned char iCode[] = {
329: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
330: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
331: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
332: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
333: 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
334: 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
335: 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
336: 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
337: };
338: assert( argc==1 );
339: zIn = argv[0];
340: for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
341: if( zIn[i] ){
342: zResult[0] = toupper(zIn[i]);
343: for(j=1; j<4 && zIn[i]; i++){
344: int code = iCode[zIn[i]&0x7f];
345: if( code>0 ){
346: zResult[j++] = code + '0';
347: }
348: }
349: while( j<4 ){
350: zResult[j++] = '0';
351: }
352: zResult[j] = 0;
353: sqlite_set_result_string(context, zResult, 4);
354: }else{
355: sqlite_set_result_string(context, "?000", 4);
356: }
357: }
358: #endif
359:
360: #ifdef SQLITE_TEST
361: /*
362: ** This function generates a string of random characters. Used for
363: ** generating test data.
364: */
365: static void randStr(sqlite_func *context, int argc, const char **argv){
366: static const unsigned char zSrc[] =
367: "abcdefghijklmnopqrstuvwxyz"
368: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
369: "0123456789"
370: ".-!,:*^+=_|?/<> ";
371: int iMin, iMax, n, r, i;
372: unsigned char zBuf[1000];
373: if( argc>=1 ){
374: iMin = atoi(argv[0]);
375: if( iMin<0 ) iMin = 0;
376: if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1;
377: }else{
378: iMin = 1;
379: }
380: if( argc>=2 ){
381: iMax = atoi(argv[1]);
382: if( iMax<iMin ) iMax = iMin;
383: if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
384: }else{
385: iMax = 50;
386: }
387: n = iMin;
388: if( iMax>iMin ){
389: sqliteRandomness(sizeof(r), &r);
390: r &= 0x7fffffff;
391: n += r%(iMax + 1 - iMin);
392: }
393: assert( n<sizeof(zBuf) );
394: sqliteRandomness(n, zBuf);
395: for(i=0; i<n; i++){
396: zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
397: }
398: zBuf[n] = 0;
399: sqlite_set_result_string(context, zBuf, n);
400: }
401: #endif
402:
403: /*
404: ** An instance of the following structure holds the context of a
405: ** sum() or avg() aggregate computation.
406: */
407: typedef struct SumCtx SumCtx;
408: struct SumCtx {
409: double sum; /* Sum of terms */
410: int cnt; /* Number of elements summed */
411: };
412:
413: /*
414: ** Routines used to compute the sum or average.
415: */
416: static void sumStep(sqlite_func *context, int argc, const char **argv){
417: SumCtx *p;
418: if( argc<1 ) return;
419: p = sqlite_aggregate_context(context, sizeof(*p));
420: if( p && argv[0] ){
421: p->sum += sqliteAtoF(argv[0], 0);
422: p->cnt++;
423: }
424: }
425: static void sumFinalize(sqlite_func *context){
426: SumCtx *p;
427: p = sqlite_aggregate_context(context, sizeof(*p));
428: sqlite_set_result_double(context, p ? p->sum : 0.0);
429: }
430: static void avgFinalize(sqlite_func *context){
431: SumCtx *p;
432: p = sqlite_aggregate_context(context, sizeof(*p));
433: if( p && p->cnt>0 ){
434: sqlite_set_result_double(context, p->sum/(double)p->cnt);
435: }
436: }
437:
438: /*
439: ** An instance of the following structure holds the context of a
440: ** variance or standard deviation computation.
441: */
442: typedef struct StdDevCtx StdDevCtx;
443: struct StdDevCtx {
444: double sum; /* Sum of terms */
445: double sum2; /* Sum of the squares of terms */
446: int cnt; /* Number of terms counted */
447: };
448:
449: #if 0 /* Omit because math library is required */
450: /*
451: ** Routines used to compute the standard deviation as an aggregate.
452: */
453: static void stdDevStep(sqlite_func *context, int argc, const char **argv){
454: StdDevCtx *p;
455: double x;
456: if( argc<1 ) return;
457: p = sqlite_aggregate_context(context, sizeof(*p));
458: if( p && argv[0] ){
459: x = sqliteAtoF(argv[0], 0);
460: p->sum += x;
461: p->sum2 += x*x;
462: p->cnt++;
463: }
464: }
465: static void stdDevFinalize(sqlite_func *context){
466: double rN = sqlite_aggregate_count(context);
467: StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p));
468: if( p && p->cnt>1 ){
469: double rCnt = cnt;
470: sqlite_set_result_double(context,
471: sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0)));
472: }
473: }
474: #endif
475:
476: /*
477: ** The following structure keeps track of state information for the
478: ** count() aggregate function.
479: */
480: typedef struct CountCtx CountCtx;
481: struct CountCtx {
482: int n;
483: };
484:
485: /*
486: ** Routines to implement the count() aggregate function.
487: */
488: static void countStep(sqlite_func *context, int argc, const char **argv){
489: CountCtx *p;
490: p = sqlite_aggregate_context(context, sizeof(*p));
491: if( (argc==0 || argv[0]) && p ){
492: p->n++;
493: }
494: }
495: static void countFinalize(sqlite_func *context){
496: CountCtx *p;
497: p = sqlite_aggregate_context(context, sizeof(*p));
498: sqlite_set_result_int(context, p ? p->n : 0);
499: }
500:
501: /*
502: ** This function tracks state information for the min() and max()
503: ** aggregate functions.
504: */
505: typedef struct MinMaxCtx MinMaxCtx;
506: struct MinMaxCtx {
507: char *z; /* The best so far */
508: char zBuf[28]; /* Space that can be used for storage */
509: };
510:
511: /*
512: ** Routines to implement min() and max() aggregate functions.
513: */
514: static void minmaxStep(sqlite_func *context, int argc, const char **argv){
515: MinMaxCtx *p;
516: int (*xCompare)(const char*, const char*);
517: int mask; /* 0 for min() or 0xffffffff for max() */
518:
519: assert( argc==2 );
520: if( argv[0]==0 ) return; /* Ignore NULL values */
521: if( argv[1][0]=='n' ){
522: xCompare = sqliteCompare;
523: }else{
524: xCompare = strcmp;
525: }
526: mask = (int)sqlite_user_data(context);
527: assert( mask==0 || mask==-1 );
528: p = sqlite_aggregate_context(context, sizeof(*p));
529: if( p==0 || argc<1 ) return;
530: if( p->z==0 || (xCompare(argv[0],p->z)^mask)<0 ){
531: int len;
532: if( p->zBuf[0] ){
533: sqliteFree(p->z);
534: }
535: len = strlen(argv[0]);
536: if( len < sizeof(p->zBuf)-1 ){
537: p->z = &p->zBuf[1];
538: p->zBuf[0] = 0;
539: }else{
540: p->z = sqliteMalloc( len+1 );
541: p->zBuf[0] = 1;
542: if( p->z==0 ) return;
543: }
544: strcpy(p->z, argv[0]);
545: }
546: }
547: static void minMaxFinalize(sqlite_func *context){
548: MinMaxCtx *p;
549: p = sqlite_aggregate_context(context, sizeof(*p));
550: if( p && p->z && p->zBuf[0]<2 ){
551: sqlite_set_result_string(context, p->z, strlen(p->z));
552: }
553: if( p && p->zBuf[0] ){
554: sqliteFree(p->z);
555: }
556: }
557:
558: /*
559: ** This function registered all of the above C functions as SQL
560: ** functions. This should be the only routine in this file with
561: ** external linkage.
562: */
563: void sqliteRegisterBuiltinFunctions(sqlite *db){
564: static struct {
565: char *zName;
566: signed char nArg;
567: signed char dataType;
568: u8 argType; /* 0: none. 1: db 2: (-1) */
569: void (*xFunc)(sqlite_func*,int,const char**);
570: } aFuncs[] = {
571: { "min", -1, SQLITE_ARGS, 0, minmaxFunc },
572: { "min", 0, 0, 0, 0 },
573: { "max", -1, SQLITE_ARGS, 2, minmaxFunc },
574: { "max", 0, 0, 2, 0 },
575: { "typeof", 1, SQLITE_TEXT, 0, typeofFunc },
576: { "length", 1, SQLITE_NUMERIC, 0, lengthFunc },
577: { "substr", 3, SQLITE_TEXT, 0, substrFunc },
578: { "abs", 1, SQLITE_NUMERIC, 0, absFunc },
579: { "round", 1, SQLITE_NUMERIC, 0, roundFunc },
580: { "round", 2, SQLITE_NUMERIC, 0, roundFunc },
581: { "upper", 1, SQLITE_TEXT, 0, upperFunc },
582: { "lower", 1, SQLITE_TEXT, 0, lowerFunc },
583: { "coalesce", -1, SQLITE_ARGS, 0, ifnullFunc },
584: { "coalesce", 0, 0, 0, 0 },
585: { "coalesce", 1, 0, 0, 0 },
586: { "ifnull", 2, SQLITE_ARGS, 0, ifnullFunc },
587: { "random", -1, SQLITE_NUMERIC, 0, randomFunc },
588: { "like", 2, SQLITE_NUMERIC, 0, likeFunc },
589: { "glob", 2, SQLITE_NUMERIC, 0, globFunc },
590: { "nullif", 2, SQLITE_ARGS, 0, nullifFunc },
591: { "sqlite_version",0,SQLITE_TEXT, 0, versionFunc},
592: { "quote", 1, SQLITE_ARGS, 0, quoteFunc },
593: { "last_insert_rowid", 0, SQLITE_NUMERIC, 1, last_insert_rowid },
594: { "change_count", 0, SQLITE_NUMERIC, 1, change_count },
595: { "last_statement_change_count",
596: 0, SQLITE_NUMERIC, 1, last_statement_change_count },
597: #ifdef SQLITE_SOUNDEX
598: { "soundex", 1, SQLITE_TEXT, 0, soundexFunc},
599: #endif
600: #ifdef SQLITE_TEST
601: { "randstr", 2, SQLITE_TEXT, 0, randStr },
602: #endif
603: };
604: static struct {
605: char *zName;
606: signed char nArg;
607: signed char dataType;
608: u8 argType;
609: void (*xStep)(sqlite_func*,int,const char**);
610: void (*xFinalize)(sqlite_func*);
611: } aAggs[] = {
612: { "min", 1, 0, 0, minmaxStep, minMaxFinalize },
613: { "max", 1, 0, 2, minmaxStep, minMaxFinalize },
614: { "sum", 1, SQLITE_NUMERIC, 0, sumStep, sumFinalize },
615: { "avg", 1, SQLITE_NUMERIC, 0, sumStep, avgFinalize },
616: { "count", 0, SQLITE_NUMERIC, 0, countStep, countFinalize },
617: { "count", 1, SQLITE_NUMERIC, 0, countStep, countFinalize },
618: #if 0
619: { "stddev", 1, SQLITE_NUMERIC, 0, stdDevStep, stdDevFinalize },
620: #endif
621: };
622: static const char *azTypeFuncs[] = { "min", "max", "typeof" };
623: int i;
624:
625: for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
626: void *pArg;
627: switch( aFuncs[i].argType ){
628: case 0: pArg = 0; break;
629: case 1: pArg = db; break;
630: case 2: pArg = (void*)(-1); break;
631: }
632: sqlite_create_function(db, aFuncs[i].zName,
633: aFuncs[i].nArg, aFuncs[i].xFunc, pArg);
634: if( aFuncs[i].xFunc ){
635: sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
636: }
637: }
638: for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
639: void *pArg;
640: switch( aAggs[i].argType ){
641: case 0: pArg = 0; break;
642: case 1: pArg = db; break;
643: case 2: pArg = (void*)(-1); break;
644: }
645: sqlite_create_aggregate(db, aAggs[i].zName,
646: aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, pArg);
647: sqlite_function_type(db, aAggs[i].zName, aAggs[i].dataType);
648: }
649: for(i=0; i<sizeof(azTypeFuncs)/sizeof(azTypeFuncs[0]); i++){
650: int n = strlen(azTypeFuncs[i]);
651: FuncDef *p = sqliteHashFind(&db->aFunc, azTypeFuncs[i], n);
652: while( p ){
653: p->includeTypes = 1;
654: p = p->pNext;
655: }
656: }
657: sqliteRegisterDateTimeFunctions(db);
658: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>