/ Check-in [0eef538f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added length() and substr() functions (CVS 143)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0eef538f3de66fede7c88f8be8c3458d84107c3f
User & Date: drh 2000-08-28 15:51:44
Context
2000-08-28
16:21
adding length() and substr() tests. fix shell.c bug (CVS 144) check-in: b8cec9b9 user: drh tags: trunk
15:51
Added length() and substr() functions (CVS 143) check-in: 0eef538f user: drh tags: trunk
2000-08-22
18:30
Version 1.0.3 (CVS 497) check-in: d35a1f8b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

    20     20   **   drh@hwaci.com
    21     21   **   http://www.hwaci.com/drh/
    22     22   **
    23     23   *************************************************************************
    24     24   ** This file contains routines used for analyzing expressions and
    25     25   ** for generating VDBE code that evaluates expressions.
    26     26   **
    27         -** $Id: expr.c,v 1.18 2000/06/21 13:59:11 drh Exp $
           27  +** $Id: expr.c,v 1.19 2000/08/28 15:51:44 drh Exp $
    28     28   */
    29     29   #include "sqliteInt.h"
    30     30   
    31     31   /*
    32     32   ** Walk an expression tree.  Return 1 if the expression is constant
    33     33   ** and 0 if it involves variables.
    34     34   */
................................................................................
   319    319     } aFunc[] = {
   320    320        { "count",  5, FN_Count },
   321    321        { "min",    3, FN_Min   },
   322    322        { "max",    3, FN_Max   },
   323    323        { "sum",    3, FN_Sum   },
   324    324        { "avg",    3, FN_Avg   },
   325    325        { "fcnt",   4, FN_Fcnt  },  /* Used for testing only */
          326  +     { "length", 6, FN_Length},
          327  +     { "substr", 6, FN_Substr},
   326    328     };
   327    329     int i;
   328    330     for(i=0; i<ArraySize(aFunc); i++){
   329    331       if( aFunc[i].len==pToken->n 
   330    332        && sqliteStrNICmp(pToken->z, aFunc[i].zName, aFunc[i].len)==0 ){
   331    333          return aFunc[i].id;
   332    334       }
................................................................................
   376    378           case FN_Avg:
   377    379           case FN_Sum: {
   378    380             no_such_func = !allowAgg;
   379    381             too_many_args = n>1;
   380    382             too_few_args = n<1;
   381    383             is_agg = 1;
   382    384             break;
          385  +        }
          386  +        case FN_Length: {
          387  +          too_few_args = n<1;
          388  +          too_many_args = n>1;
          389  +          break;
          390  +        }
          391  +        case FN_Substr: {
          392  +          too_few_args = n<3;
          393  +          too_many_args = n>3;
          394  +          break;
   383    395           }
   384    396           /* The "fcnt(*)" function always returns the number of fetch
   385    397           ** operations that have occurred so far while processing the
   386    398           ** SQL statement.  This information can be used by test procedures
   387    399           ** to verify that indices are being used properly to minimize
   388    400           ** searching.  All arguments to fcnt() are ignored.  fcnt() has
   389    401           ** no use (other than testing) that we are aware of.
   390    402           */
   391    403           case FN_Fcnt: {
   392    404             n = 0;
   393    405             break;
   394    406           }
          407  +      
   395    408           default: break;
   396    409         }
   397    410         if( no_such_func ){
   398    411           sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1,
   399    412              pExpr->token.z, pExpr->token.n, 0);
   400    413           pParse->nErr++;
   401    414           nErr++;
................................................................................
   570    583         break;
   571    584       }
   572    585       case TK_FUNCTION: {
   573    586         int id = pExpr->iColumn;
   574    587         int op;
   575    588         int i;
   576    589         ExprList *pList = pExpr->pList;
   577         -      if( id==FN_Fcnt ){
   578         -        sqliteVdbeAddOp(v, OP_Fcnt, 0, 0, 0, 0);
   579         -        break;
   580         -      }
   581         -      op = id==FN_Min ? OP_Min : OP_Max;
   582         -      for(i=0; i<pList->nExpr; i++){
   583         -        sqliteExprCode(pParse, pList->a[i].pExpr);
   584         -        if( i>0 ){
   585         -          sqliteVdbeAddOp(v, op, 0, 0, 0, 0);
          590  +      switch( id ){
          591  +        case FN_Fcnt: {
          592  +          sqliteVdbeAddOp(v, OP_Fcnt, 0, 0, 0, 0);
          593  +          break;
          594  +        }
          595  +        case FN_Min: 
          596  +        case FN_Max: {
          597  +          op = id==FN_Min ? OP_Min : OP_Max;
          598  +          for(i=0; i<pList->nExpr; i++){
          599  +            sqliteExprCode(pParse, pList->a[i].pExpr);
          600  +            if( i>0 ){
          601  +              sqliteVdbeAddOp(v, op, 0, 0, 0, 0);
          602  +            }
          603  +          }
          604  +          break;
          605  +        }
          606  +        case FN_Length: {
          607  +          sqliteExprCode(pParse, pList->a[0].pExpr);
          608  +          sqliteVdbeAddOp(v, OP_Strlen, 0, 0, 0, 0);
          609  +          break;
          610  +        }
          611  +        case FN_Substr: {
          612  +          for(i=0; i<pList->nExpr; i++){
          613  +            sqliteExprCode(pParse, pList->a[i].pExpr);
          614  +          }
          615  +          sqliteVdbeAddOp(v, OP_Substr, 0, 0, 0, 0);
          616  +          break;
          617  +        }
          618  +        default: {
          619  +          /* Can't happen! */
          620  +          break;
   586    621           }
   587    622         }
   588    623         break;
   589    624       }
   590    625       case TK_SELECT: {
   591    626         sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0, 0, 0);
   592    627         break;

Changes to src/sqliteInt.h.

    19     19   ** Author contact information:
    20     20   **   drh@hwaci.com
    21     21   **   http://www.hwaci.com/drh/
    22     22   **
    23     23   *************************************************************************
    24     24   ** Internal interface definitions for SQLite.
    25     25   **
    26         -** @(#) $Id: sqliteInt.h,v 1.29 2000/08/02 13:47:42 drh Exp $
           26  +** @(#) $Id: sqliteInt.h,v 1.30 2000/08/28 15:51:44 drh Exp $
    27     27   */
    28     28   #include "sqlite.h"
    29     29   #include "dbbe.h"
    30     30   #include "vdbe.h"
    31     31   #include "parse.h"
    32     32   #include <gdbm.h>
    33     33   #include <stdio.h>
................................................................................
    95     95   #define FN_Unknown    0
    96     96   #define FN_Count      1
    97     97   #define FN_Min        2
    98     98   #define FN_Max        3
    99     99   #define FN_Sum        4
   100    100   #define FN_Avg        5
   101    101   #define FN_Fcnt       6
          102  +#define FN_Length     7
          103  +#define FN_Substr     8
   102    104   
   103    105   /*
   104    106   ** Forward references to structures
   105    107   */
   106    108   typedef struct Column Column;
   107    109   typedef struct Table Table;
   108    110   typedef struct Index Index;

Changes to src/vdbe.c.

    37     37   ** inplicit conversion from one type to the other occurs as necessary.
    38     38   ** 
    39     39   ** Most of the code in this file is taken up by the sqliteVdbeExec()
    40     40   ** function which does the work of interpreting a VDBE program.
    41     41   ** But other routines are also provided to help in building up
    42     42   ** a program instruction by instruction.
    43     43   **
    44         -** $Id: vdbe.c,v 1.38 2000/08/02 12:26:29 drh Exp $
           44  +** $Id: vdbe.c,v 1.39 2000/08/28 15:51:44 drh Exp $
    45     45   */
    46     46   #include "sqliteInt.h"
    47     47   #include <unistd.h>
    48     48   
    49     49   /*
    50     50   ** SQL is translated into a sequence of instructions to be
    51     51   ** executed by a virtual machine.  Each instruction is an instance
................................................................................
   784    784     "String",         "Null",           "Pop",            "Dup",
   785    785     "Pull",           "Add",            "AddImm",         "Subtract",
   786    786     "Multiply",       "Divide",         "Min",            "Max",
   787    787     "Like",           "Glob",           "Eq",             "Ne",
   788    788     "Lt",             "Le",             "Gt",             "Ge",
   789    789     "IsNull",         "NotNull",        "Negative",       "And",
   790    790     "Or",             "Not",            "Concat",         "Noop",
          791  +  "Strlen",         "Substr",       
   791    792   };
   792    793   
   793    794   /*
   794    795   ** Given the name of an opcode, return its number.  Return 0 if
   795    796   ** there is no match.
   796    797   **
   797    798   ** This routine is used for testing and debugging.
................................................................................
  3125   3126           Stringify(p, tos);
  3126   3127           if( i>=0 && i<p->nSet && !SetTest(&p->aSet[i], p->zStack[tos]) ){
  3127   3128             pc = pOp->p2 - 1;
  3128   3129           }
  3129   3130           PopStack(p, 1);
  3130   3131           break;
  3131   3132         }
         3133  +
         3134  +      /* Opcode: Length * * *
         3135  +      **
         3136  +      ** Interpret the top of the stack as a string.  Replace the top of
         3137  +      ** stack with an integer which is the length of the string.
         3138  +      */
         3139  +      case OP_Strlen: {
         3140  +        int tos = p->tos;
         3141  +        int len;
         3142  +        if( tos<0 ) goto not_enough_stack;
         3143  +        Stringify(p, tos);
         3144  +        len = p->aStack[tos].n-1;
         3145  +        PopStack(p, 1);
         3146  +        p->tos++;
         3147  +        p->aStack[tos].i = len;
         3148  +        p->aStack[tos].flags = STK_Int;
         3149  +        break;
         3150  +      }
         3151  +
         3152  +      /* Opcode: Substr P1 P2 *
         3153  +      **
         3154  +      ** This operation pops between 1 and 3 elements from the stack and
         3155  +      ** pushes back a single element.  The bottom-most element popped from
         3156  +      ** the stack is a string and the element pushed back is also a string.
         3157  +      ** The other two elements popped are integers.  The integers are taken
         3158  +      ** from the stack only if P1 and/or P2 are 0.  When P1 or P2 are
         3159  +      ** not zero, the value of the operand is used rather than the integer
         3160  +      ** from the stack.  In the sequel, we will use P1 and P2 to describe
         3161  +      ** the two integers, even if those integers are really taken from the
         3162  +      ** stack.
         3163  +      **
         3164  +      ** The string pushed back onto the stack is a substring of the string
         3165  +      ** that was popped.  There are P2 characters in the substring.  The
         3166  +      ** first character of the substring is the P1-th character of the
         3167  +      ** original string where the left-most character is 1 (not 0).  If P1
         3168  +      ** is negative, then counting begins at the right instead of at the
         3169  +      ** left.
         3170  +      */
         3171  +      case OP_Substr: {
         3172  +        int cnt;
         3173  +        int start;
         3174  +        int n;
         3175  +        char *z;
         3176  +
         3177  +        if( pOp->p2==0 ){
         3178  +          if( p->tos<0 ) goto not_enough_stack;
         3179  +          Integerify(p, p->tos);
         3180  +          cnt = p->aStack[p->tos].i;
         3181  +          PopStack(p, 1);
         3182  +        }else{
         3183  +          cnt = pOp->p2;
         3184  +        }
         3185  +        if( pOp->p1==0 ){
         3186  +          if( p->tos<0 ) goto not_enough_stack;
         3187  +          Integerify(p, p->tos);
         3188  +          start = p->aStack[p->tos].i;
         3189  +          PopStack(p, 1);
         3190  +        }else{
         3191  +          start = pOp->p1;
         3192  +        }
         3193  +        if( p->tos<0 ) goto not_enough_stack;
         3194  +        Stringify(p, p->tos);
         3195  +        n = p->aStack[p->tos].n - 1;
         3196  +        if( start<0 ){
         3197  +          start += n;
         3198  +          if( start<0 ){
         3199  +            cnt += start;
         3200  +            start = 0;
         3201  +          }
         3202  +        }
         3203  +        if( cnt<0 ) cnt = 0;
         3204  +        if( cnt > n ){
         3205  +          cnt = n;
         3206  +        }
         3207  +        z = sqliteMalloc( cnt+1 );
         3208  +        if( z==0 ) goto no_mem;
         3209  +        strncpy(z, p->zStack[p->tos], cnt);
         3210  +        z[cnt] = 0;
         3211  +        PopStack(p, 1);
         3212  +        p->tos++;
         3213  +        p->zStack[p->tos] = z;
         3214  +        p->aStack[p->tos].n = cnt + 1;
         3215  +        p->aStack[p->tos].flags = STK_Str|STK_Dyn;
         3216  +        break;
         3217  +      }
  3132   3218   
  3133   3219         /* An other opcode is illegal...
  3134   3220         */
  3135   3221         default: {
  3136   3222           sprintf(zBuf,"%d",pOp->opcode);
  3137   3223           sqliteSetString(pzErrMsg, "unknown opcode ", zBuf, 0);
  3138   3224           rc = SQLITE_INTERNAL;

Changes to src/vdbe.h.

    23     23   *************************************************************************
    24     24   ** Header file for the Virtual DataBase Engine (VDBE)
    25     25   **
    26     26   ** This header defines the interface to the virtual database engine
    27     27   ** or VDBE.  The VDBE implements an abstract machine that runs a
    28     28   ** simple program to access and modify the underlying database.
    29     29   **
    30         -** $Id: vdbe.h,v 1.11 2000/07/28 14:32:50 drh Exp $
           30  +** $Id: vdbe.h,v 1.12 2000/08/28 15:51:45 drh Exp $
    31     31   */
    32     32   #ifndef _SQLITE_VDBE_H_
    33     33   #define _SQLITE_VDBE_H_
    34     34   #include <stdio.h>
    35     35   
    36     36   /*
    37     37   ** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
   169    169   #define OP_Negative           83
   170    170   #define OP_And                84
   171    171   #define OP_Or                 85
   172    172   #define OP_Not                86
   173    173   #define OP_Concat             87
   174    174   #define OP_Noop               88
   175    175   
   176         -#define OP_MAX                88
          176  +#define OP_Strlen             89
          177  +#define OP_Substr             90
          178  +
          179  +#define OP_MAX                90
   177    180   
   178    181   /*
   179    182   ** Prototypes for the VDBE interface.  See comments on the implementation
   180    183   ** for a description of what each of these routines does.
   181    184   */
   182    185   Vdbe *sqliteVdbeCreate(Dbbe*);
   183    186   int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);