mirror of
				https://github.com/sqlite/sqlite.git
				synced 2025-10-24 09:53:10 +03:00 
			
		
		
		
	Change functions to handle NULLs correctly. Added the NULLIF() function. (CVS 590)
FossilOrigin-Name: 46ce1a9ab6e527958ebc757fa2175c488299cd84
This commit is contained in:
		
							
								
								
									
										14
									
								
								manifest
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								manifest
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| C NULL\svalues\sare\sdistinct.\s\sA\scomparison\sinvolving\sa\sNULL\sis\salways\sfalse.\nOperations\son\sa\sNULL\svalue\syield\sa\sNULL\sresult.\s\sThis\schange\smakes\sSQLite\noperate\smore\slike\sthe\sSQL\sspec,\sbut\sit\smay\sbreak\sexisting\sapplications\sthat\nassumed\sthe\sold\sbehavior.\s\sAll\sthe\sold\stests\spass\sbut\swe\sstill\sneed\sto\sadd\nnew\stests\sto\sbetter\sverify\sthe\snew\sbehavior.\s\sFix\sfor\sticket\s#44.\s(CVS\s589) | C Change\sfunctions\sto\shandle\sNULLs\scorrectly.\s\sAdded\sthe\sNULLIF()\sfunction.\s(CVS\s590) | ||||||
| D 2002-05-26T20:54:33 | D 2002-05-26T21:34:58 | ||||||
| F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c | F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c | ||||||
| F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 | F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 | ||||||
| F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 | F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 | ||||||
| @@ -24,7 +24,7 @@ F src/build.c 36e42718a7a94f554ea39508993378482f5335c7 | |||||||
| F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523 | F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523 | ||||||
| F src/encode.c 346b12b46148506c32038524b95c4631ab46d760 | F src/encode.c 346b12b46148506c32038524b95c4631ab46d760 | ||||||
| F src/expr.c 1a7a2f5f2b7dd37659783cdb6efaac74a092ba71 | F src/expr.c 1a7a2f5f2b7dd37659783cdb6efaac74a092ba71 | ||||||
| F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce | F src/func.c 16e994eea8cceb0cd451938e63d337f7d9d089bf | ||||||
| F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72 | F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72 | ||||||
| F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9 | F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9 | ||||||
| F src/insert.c 24b4e146319bada6f82a1d5eae6b38b3065d132f | F src/insert.c 24b4e146319bada6f82a1d5eae6b38b3065d132f | ||||||
| @@ -51,7 +51,7 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f | |||||||
| F src/tokenize.c facec7dc0b4a13e17ad67702f548dac2f7c6a732 | F src/tokenize.c facec7dc0b4a13e17ad67702f548dac2f7c6a732 | ||||||
| F src/trigger.c f9adb404ea355a8be2c9cd9740794a898cf1096c | F src/trigger.c f9adb404ea355a8be2c9cd9740794a898cf1096c | ||||||
| F src/update.c f68375173bf5338cae3e97012708e10f206aedd9 | F src/update.c f68375173bf5338cae3e97012708e10f206aedd9 | ||||||
| F src/util.c 707c30f8c13cddace7c08556ac450c0b786660b3 | F src/util.c a9f6e6f03e8b7137204ac15b35a58f321e38037e | ||||||
| F src/vdbe.c caa269517b2392986c8f55401f272e76b9de82d9 | F src/vdbe.c caa269517b2392986c8f55401f272e76b9de82d9 | ||||||
| F src/vdbe.h b8706429131c14b307a07aab7e47f95a9da53610 | F src/vdbe.h b8706429131c14b307a07aab7e47f95a9da53610 | ||||||
| F src/where.c b054f2f23127bd57eb5f973bcd38764b875d73fe | F src/where.c b054f2f23127bd57eb5f973bcd38764b875d73fe | ||||||
| @@ -135,7 +135,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f | |||||||
| F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 | F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 | ||||||
| F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 | F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 | ||||||
| F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 | F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 | ||||||
| P d8d04c14f18d1feba89ccea0be70530a18248c51 | P 9051173742f1b0e15a809d12a0c9c98fd2c4614d | ||||||
| R 2ee233b2a9ebb3e4a8fe3e93b3747a0c | R 0620e522ec88d7386c2177fd29ebfac3 | ||||||
| U drh | U drh | ||||||
| Z f507bf5d6b83b961339e312ca54783e8 | Z 0624defcbccb679d773bc9ffe5a1ecda | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| 9051173742f1b0e15a809d12a0c9c98fd2c4614d | 46ce1a9ab6e527958ebc757fa2175c488299cd84 | ||||||
							
								
								
									
										88
									
								
								src/func.c
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								src/func.c
									
									
									
									
									
								
							| @@ -16,7 +16,7 @@ | |||||||
| ** sqliteRegisterBuildinFunctions() found at the bottom of the file. | ** sqliteRegisterBuildinFunctions() found at the bottom of the file. | ||||||
| ** All other code has file scope. | ** All other code has file scope. | ||||||
| ** | ** | ||||||
| ** $Id: func.c,v 1.16 2002/04/20 14:24:42 drh Exp $ | ** $Id: func.c,v 1.17 2002/05/26 21:34:58 drh Exp $ | ||||||
| */ | */ | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| #include <math.h> | #include <math.h> | ||||||
| @@ -33,7 +33,9 @@ static void minFunc(sqlite_func *context, int argc, const char **argv){ | |||||||
|  |  | ||||||
|   if( argc==0 ) return; |   if( argc==0 ) return; | ||||||
|   zBest = argv[0]; |   zBest = argv[0]; | ||||||
|  |   if( zBest==0 ) return; | ||||||
|   for(i=1; i<argc; i++){ |   for(i=1; i<argc; i++){ | ||||||
|  |     if( argv[i]==0 ) return; | ||||||
|     if( sqliteCompare(argv[i], zBest)<0 ){ |     if( sqliteCompare(argv[i], zBest)<0 ){ | ||||||
|       zBest = argv[i]; |       zBest = argv[i]; | ||||||
|     } |     } | ||||||
| @@ -46,7 +48,9 @@ static void maxFunc(sqlite_func *context, int argc, const char **argv){ | |||||||
|  |  | ||||||
|   if( argc==0 ) return; |   if( argc==0 ) return; | ||||||
|   zBest = argv[0]; |   zBest = argv[0]; | ||||||
|  |   if( zBest==0 ) return; | ||||||
|   for(i=1; i<argc; i++){ |   for(i=1; i<argc; i++){ | ||||||
|  |     if( argv[i]==0 ) return; | ||||||
|     if( sqliteCompare(argv[i], zBest)>0 ){ |     if( sqliteCompare(argv[i], zBest)>0 ){ | ||||||
|       zBest = argv[i]; |       zBest = argv[i]; | ||||||
|     } |     } | ||||||
| @@ -63,15 +67,12 @@ static void lengthFunc(sqlite_func *context, int argc, const char **argv){ | |||||||
|  |  | ||||||
|   assert( argc==1 ); |   assert( argc==1 ); | ||||||
|   z = argv[0]; |   z = argv[0]; | ||||||
|   if( z==0 ){ |   if( z==0 ) return; | ||||||
|     len = 0; |  | ||||||
|   }else{ |  | ||||||
| #ifdef SQLITE_UTF8 | #ifdef SQLITE_UTF8 | ||||||
|     for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; } |   for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; } | ||||||
| #else | #else | ||||||
|     len = strlen(z); |   len = strlen(z); | ||||||
| #endif | #endif | ||||||
|   } |  | ||||||
|   sqlite_set_result_int(context, len); |   sqlite_set_result_int(context, len); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -82,7 +83,8 @@ static void absFunc(sqlite_func *context, int argc, const char **argv){ | |||||||
|   const char *z; |   const char *z; | ||||||
|   assert( argc==1 ); |   assert( argc==1 ); | ||||||
|   z = argv[0]; |   z = argv[0]; | ||||||
|   if( z && z[0]=='-' && isdigit(z[1]) ) z++; |   if( z==0 ) return; | ||||||
|  |   if( z[0]=='-' && isdigit(z[1]) ) z++; | ||||||
|   sqlite_set_result_string(context, z, -1); |   sqlite_set_result_string(context, z, -1); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -142,10 +144,11 @@ static void roundFunc(sqlite_func *context, int argc, const char **argv){ | |||||||
|   double r; |   double r; | ||||||
|   char zBuf[100]; |   char zBuf[100]; | ||||||
|   assert( argc==1 || argc==2 ); |   assert( argc==1 || argc==2 ); | ||||||
|   n = argc==2 && argv[1] ? atoi(argv[1]) : 0; |   if( argv[0]==0 || (argc==2 && argv[1]==0) ) return; | ||||||
|  |   n = argc==2 ? atoi(argv[1]) : 0; | ||||||
|   if( n>30 ) n = 30; |   if( n>30 ) n = 30; | ||||||
|   if( n<0 ) n = 0; |   if( n<0 ) n = 0; | ||||||
|   r = argv[0] ? atof(argv[0]) : 0.0; |   r = atof(argv[0]); | ||||||
|   sprintf(zBuf,"%.*f",n,r); |   sprintf(zBuf,"%.*f",n,r); | ||||||
|   sqlite_set_result_string(context, zBuf, -1); |   sqlite_set_result_string(context, zBuf, -1); | ||||||
| } | } | ||||||
| @@ -215,8 +218,8 @@ static void last_insert_rowid(sqlite_func *context, int arg, const char **argv){ | |||||||
| ** is implemented as like(A,B). | ** is implemented as like(A,B). | ||||||
| */ | */ | ||||||
| static void likeFunc(sqlite_func *context, int arg, const char **argv){ | static void likeFunc(sqlite_func *context, int arg, const char **argv){ | ||||||
|   sqlite_set_result_int(context,  |   if( argv[0]==0 || argv[1]==0 ) return; | ||||||
|      sqliteLikeCompare(argv[0] ? argv[0] : "",argv[1] ? argv[1] : "")); |   sqlite_set_result_int(context, sqliteLikeCompare(argv[0], argv[1])); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -229,8 +232,19 @@ static void likeFunc(sqlite_func *context, int arg, const char **argv){ | |||||||
| ** is implemented as glob(A,B). | ** is implemented as glob(A,B). | ||||||
| */ | */ | ||||||
| static void globFunc(sqlite_func *context, int arg, const char **argv){ | static void globFunc(sqlite_func *context, int arg, const char **argv){ | ||||||
|   sqlite_set_result_int(context, |   if( argv[0]==0 || argv[1]==0 ) return; | ||||||
|     sqliteGlobCompare(argv[0] ? argv[0] : "",argv[1] ? argv[1] : "")); |   sqlite_set_result_int(context, sqliteGlobCompare(argv[0], argv[1])); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ** Implementation of the NULLIF(x,y) function.  The result is the first | ||||||
|  | ** argument if the arguments are different.  The result is NULL if the | ||||||
|  | ** arguments are equal to each other. | ||||||
|  | */ | ||||||
|  | static void nullifFunc(sqlite_func *context, int argc, const char **argv){ | ||||||
|  |   if( argv[0]!=0 && sqliteCompare(argv[0],argv[1])!=0 ){ | ||||||
|  |     sqlite_set_result_string(context, argv[0], -1); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -334,6 +348,7 @@ static void countFinalize(sqlite_func *context){ | |||||||
| */ | */ | ||||||
| typedef struct MinMaxCtx MinMaxCtx; | typedef struct MinMaxCtx MinMaxCtx; | ||||||
| struct MinMaxCtx { | struct MinMaxCtx { | ||||||
|  |   int isNull;      /* True if the result should be NULL */ | ||||||
|   char *z;         /* The best so far */ |   char *z;         /* The best so far */ | ||||||
|   char zBuf[28];   /* Space that can be used for storage */ |   char zBuf[28];   /* Space that can be used for storage */ | ||||||
| }; | }; | ||||||
| @@ -345,50 +360,52 @@ static void minStep(sqlite_func *context, int argc, const char **argv){ | |||||||
|   MinMaxCtx *p; |   MinMaxCtx *p; | ||||||
|   p = sqlite_aggregate_context(context, sizeof(*p)); |   p = sqlite_aggregate_context(context, sizeof(*p)); | ||||||
|   if( p==0 || argc<1 ) return; |   if( p==0 || argc<1 ) return; | ||||||
|  |   if( argv[0]==0 || p->isNull ){ | ||||||
|  |     p->isNull = 1; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|   if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)<0 ){ |   if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)<0 ){ | ||||||
|  |     int len; | ||||||
|     if( p->z && p->z!=p->zBuf ){ |     if( p->z && p->z!=p->zBuf ){ | ||||||
|       sqliteFree(p->z); |       sqliteFree(p->z); | ||||||
|     } |     } | ||||||
|     if( argv[0] ){ |     len = strlen(argv[0]); | ||||||
|       int len = strlen(argv[0]); |     if( len < sizeof(p->zBuf) ){ | ||||||
|       if( len < sizeof(p->zBuf) ){ |       p->z = p->zBuf; | ||||||
|         p->z = p->zBuf; |  | ||||||
|       }else{ |  | ||||||
|         p->z = sqliteMalloc( len+1 ); |  | ||||||
|         if( p->z==0 ) return; |  | ||||||
|       } |  | ||||||
|       strcpy(p->z, argv[0]); |  | ||||||
|     }else{ |     }else{ | ||||||
|       p->z = 0; |       p->z = sqliteMalloc( len+1 ); | ||||||
|  |       if( p->z==0 ) return; | ||||||
|     } |     } | ||||||
|  |     strcpy(p->z, argv[0]); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| static void maxStep(sqlite_func *context, int argc, const char **argv){ | static void maxStep(sqlite_func *context, int argc, const char **argv){ | ||||||
|   MinMaxCtx *p; |   MinMaxCtx *p; | ||||||
|   p = sqlite_aggregate_context(context, sizeof(*p)); |   p = sqlite_aggregate_context(context, sizeof(*p)); | ||||||
|   if( p==0 || argc<1 ) return; |   if( p==0 || argc<1 ) return; | ||||||
|  |   if( argv[0]==0 || p->isNull ){ | ||||||
|  |     p->isNull = 1; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|   if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)>0 ){ |   if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)>0 ){ | ||||||
|  |     int len; | ||||||
|     if( p->z && p->z!=p->zBuf ){ |     if( p->z && p->z!=p->zBuf ){ | ||||||
|       sqliteFree(p->z); |       sqliteFree(p->z); | ||||||
|     } |     } | ||||||
|     if( argv[0] ){ |     len = strlen(argv[0]); | ||||||
|       int len = strlen(argv[0]); |     if( len < sizeof(p->zBuf) ){ | ||||||
|       if( len < sizeof(p->zBuf) ){ |       p->z = p->zBuf; | ||||||
|         p->z = p->zBuf; |  | ||||||
|       }else{ |  | ||||||
|         p->z = sqliteMalloc( len+1 ); |  | ||||||
|         if( p->z==0 ) return; |  | ||||||
|       } |  | ||||||
|       strcpy(p->z, argv[0]); |  | ||||||
|     }else{ |     }else{ | ||||||
|       p->z = 0; |       p->z = sqliteMalloc( len+1 ); | ||||||
|  |       if( p->z==0 ) return; | ||||||
|     } |     } | ||||||
|  |     strcpy(p->z, argv[0]); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| static void minMaxFinalize(sqlite_func *context){ | static void minMaxFinalize(sqlite_func *context){ | ||||||
|   MinMaxCtx *p; |   MinMaxCtx *p; | ||||||
|   p = sqlite_aggregate_context(context, sizeof(*p)); |   p = sqlite_aggregate_context(context, sizeof(*p)); | ||||||
|   if( p && p->z ){ |   if( p && p->z && !p->isNull ){ | ||||||
|     sqlite_set_result_string(context, p->z, strlen(p->z)); |     sqlite_set_result_string(context, p->z, strlen(p->z)); | ||||||
|   } |   } | ||||||
|   if( p && p->z && p->z!=p->zBuf ){ |   if( p && p->z && p->z!=p->zBuf ){ | ||||||
| @@ -424,6 +441,7 @@ void sqliteRegisterBuildinFunctions(sqlite *db){ | |||||||
|     { "random",    -1, randomFunc }, |     { "random",    -1, randomFunc }, | ||||||
|     { "like",       2, likeFunc   }, |     { "like",       2, likeFunc   }, | ||||||
|     { "glob",       2, globFunc   }, |     { "glob",       2, globFunc   }, | ||||||
|  |     { "nullif",     2, nullifFunc }, | ||||||
|   }; |   }; | ||||||
|   static struct { |   static struct { | ||||||
|     char *zName; |     char *zName; | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ | |||||||
| ** This file contains functions for allocating memory, comparing | ** This file contains functions for allocating memory, comparing | ||||||
| ** strings, and stuff like that. | ** strings, and stuff like that. | ||||||
| ** | ** | ||||||
| ** $Id: util.c,v 1.43 2002/05/10 13:14:07 drh Exp $ | ** $Id: util.c,v 1.44 2002/05/26 21:34:58 drh Exp $ | ||||||
| */ | */ | ||||||
| #include "sqliteInt.h" | #include "sqliteInt.h" | ||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| @@ -665,7 +665,7 @@ int sqliteCompare(const char *atext, const char *btext){ | |||||||
|   int result; |   int result; | ||||||
|   int isNumA, isNumB; |   int isNumA, isNumB; | ||||||
|   if( atext==0 ){ |   if( atext==0 ){ | ||||||
|     return -(btext!=0); |     return -1; | ||||||
|   }else if( btext==0 ){ |   }else if( btext==0 ){ | ||||||
|     return 1; |     return 1; | ||||||
|   } |   } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user