]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the printf() SQL function.
authordrh <drh@noemail.net>
Tue, 17 Dec 2013 15:03:06 +0000 (15:03 +0000)
committerdrh <drh@noemail.net>
Tue, 17 Dec 2013 15:03:06 +0000 (15:03 +0000)
FossilOrigin-Name: 6db7052eeefafdbf26b3153bc38600fecfb53ae6

manifest
manifest.uuid
src/func.c
src/printf.c
src/sqliteInt.h
src/vdbetrace.c
test/printf2.test [new file with mode: 0644]

index 92e7b53f9fb2ccee803c033a92086f2894e37fff..04c30af9edae8b82e3645759671cbb365a848e57 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Allow\sthe\sSQLITE_DETERMINISTIC\sflag\sto\sbe\sORed\sinto\sthe\spreferred\stext\sencoding\nof\sapplication-defined\sfunctions,\sto\smark\sthe\sfunction\sas\sdeterministic.
-D 2013-12-14T13:44:22.886
+C Add\sthe\sprintf()\sSQL\sfunction.
+D 2013-12-17T15:03:06.814
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -178,7 +178,7 @@ F src/delete.c b36db1f79ee50eaca979660c9dd36437f5410b93
 F src/expr.c 31a2b65339f6c3795d4cfa5e99798cd72f9fdfdf
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
-F src/func.c fed87f35cf4da4a798b726d84abefc209b48d831
+F src/func.c 6325ac2ec10833ccf4d5c36d323709221d37ea19
 F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
@@ -215,7 +215,7 @@ F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
 F src/pcache1.c 57fee9a9a617218f5037afbbe49b09da65bde56b
 F src/pragma.c 5ab7279d132143feb77f773688a24ab05da75fd7
 F src/prepare.c 359d1a1e9c9bd4488e4dd3a1aaaf2d2ebb9bb768
-F src/printf.c ba8b28e9d4ce984430e9f33f6ef1c85a1826d1dd
+F src/printf.c 0c0cb58e43410d6237afe0f2751f265fc62eac59
 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
 F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
@@ -224,7 +224,7 @@ F src/shell.c 18924f6ccfa70da98bf9e388bab512c0fd1e792e
 F src/sqlite.h.in 4ef56464aeaa3785a2c5ca37fb3a0fb229d68b2e
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h 3c1c14a551b019c94e1addcb67d92dd14a62e058
+F src/sqliteInt.h b7e9da87740488671cfe4c70038a8eef3a1d317e
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -288,7 +288,7 @@ F src/vdbeaux.c a22cbd91b24503b82690cb03324ffec9f4ef63f6
 F src/vdbeblob.c 8cd05a5630e6d5563ad017bf82edaf812b28acde
 F src/vdbemem.c 0e69351b2c6ff7d8b638688c0ae336a26befa6b2
 F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
-F src/vdbetrace.c f7eb148eb3b4fa3401b20024630dcb43d322e73c
+F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
 F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
@@ -739,6 +739,7 @@ F test/permutations.test af3278cbea3a19e025d5169be8193ff48dc3f862
 F test/pragma.test e882183ecd21d064cec5c7aaea174fbd36293429
 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
+F test/printf2.test 7b1c2c27826702723ad2b1fcd92bce2ffc9f45f3
 F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
 F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
@@ -1146,7 +1147,10 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P bc5febef921bd12ca7760e9d07d3be0e67140320
-R 08fd6b0f6ffb77c364a2bec4efb57810
+P 5716fc2341ddd8cf64139e7168597f864da4e10b
+R 2b8d4659fa3fad9afbe93191f7aa6089
+T *branch * printf-sql-function
+T *sym-printf-sql-function *
+T -sym-trunk *
 U drh
-Z d2313ea9b793ebbfa6428f7e8b022d58
+Z 77c6ba366806353f9c00efecee393357
index 0d64591d7bbff8e7c3c5336ad8b61d5e1064b9b5..ce69d4e663052fd0a135f00cf6ca7bf6d8386750 100644 (file)
@@ -1 +1 @@
-5716fc2341ddd8cf64139e7168597f864da4e10b
\ No newline at end of file
+6db7052eeefafdbf26b3153bc38600fecfb53ae6
\ No newline at end of file
index 951af97b35cd4e4406e8eb4236c7dd1b07db6372..1d6ec9f6ee34b0c54226dfeec08d51422c3b415f 100644 (file)
@@ -218,6 +218,32 @@ static void instrFunc(
   sqlite3_result_int(context, N);
 }
 
+/*
+** Implementation of the printf() function.
+*/
+static void printfFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  PrintfArguments x;
+  StrAccum str;
+  const char *zFormat;
+  int n;
+
+  if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){
+    x.nArg = argc-1;
+    x.nUsed = 0;
+    x.apArg = argv+1;
+    sqlite3StrAccumInit(&str, 0, 0, SQLITE_MAX_LENGTH);
+    str.db = sqlite3_context_db_handle(context);
+    sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x);
+    n = str.nChar;
+    sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
+                        SQLITE_DYNAMIC);
+  }
+}
+
 /*
 ** Implementation of the substr() function.
 **
@@ -1648,6 +1674,7 @@ void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(instr,              2, 0, 0, instrFunc        ),
     FUNCTION(substr,             2, 0, 0, substrFunc       ),
     FUNCTION(substr,             3, 0, 0, substrFunc       ),
+    FUNCTION(printf,            -1, 0, 0, printfFunc       ),
     FUNCTION(unicode,            1, 0, 0, unicodeFunc      ),
     FUNCTION(char,              -1, 0, 0, charFunc         ),
     FUNCTION(abs,                1, 0, 0, absFunc          ),
index 3279a54f218ad7b7d4c36ad64f326cb408e737c1..da118818bb5ef5967601882151246ac12979234a 100644 (file)
@@ -151,11 +151,28 @@ void sqlite3AppendSpace(StrAccum *pAccum, int N){
 /*
 ** Set the StrAccum object to an error mode.
 */
-void setStrAccumError(StrAccum *p, u8 eError){
+static void setStrAccumError(StrAccum *p, u8 eError){
   p->accError = eError;
   p->nAlloc = 0;
 }
 
+/*
+** Extra argument values from a PrintfArguments object
+*/
+static sqlite3_int64 getIntArg(PrintfArguments *p){
+  if( p->nArg<=p->nUsed ) return 0;
+  return sqlite3_value_int64(p->apArg[p->nUsed++]);
+}
+static double getDoubleArg(PrintfArguments *p){
+  if( p->nArg<=p->nUsed ) return 0.0;
+  return sqlite3_value_double(p->apArg[p->nUsed++]);
+}
+static char *getTextArg(PrintfArguments *p){
+  if( p->nArg<=p->nUsed ) return 0;
+  return (char*)sqlite3_value_text(p->apArg[p->nUsed++]);
+}
+
+
 /*
 ** On machines with a small stack size, you can redefine the
 ** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.
@@ -169,10 +186,10 @@ void setStrAccumError(StrAccum *p, u8 eError){
 ** Render a string given by "fmt" into the StrAccum object.
 */
 void sqlite3VXPrintf(
-  StrAccum *pAccum,                  /* Accumulate results here */
-  int useExtended,                   /* Allow extended %-conversions */
-  const char *fmt,                   /* Format string */
-  va_list ap                         /* arguments */
+  StrAccum *pAccum,          /* Accumulate results here */
+  u32 bFlags,                /* SQLITE_PRINTF_* flags */
+  const char *fmt,           /* Format string */
+  va_list ap                 /* arguments */
 ){
   int c;                     /* Next character in the format string */
   char *bufpt;               /* Pointer to the conversion buffer */
@@ -190,6 +207,8 @@ void sqlite3VXPrintf(
   etByte flag_longlong;      /* True if the "ll" flag is present */
   etByte done;               /* Loop termination flag */
   etByte xtype = 0;          /* Conversion paradigm */
+  u8 bArgList;               /* True for SQLITE_PRINTF_SQLFUNC */
+  u8 useIntern;              /* Ok to use internal conversions (ex: %T) */
   char prefix;               /* Prefix character.  "+" or "-" or " " or '\0'. */
   sqlite_uint64 longvalue;   /* Value for integer types */
   LONGDOUBLE_TYPE realvalue; /* Value for real types */
@@ -204,9 +223,18 @@ void sqlite3VXPrintf(
   etByte flag_dp;            /* True if decimal point should be shown */
   etByte flag_rtz;           /* True if trailing zeros should be removed */
 #endif
+  PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
   char buf[etBUFSIZE];       /* Conversion buffer */
 
   bufpt = 0;
+  if( bFlags ){
+    if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
+      pArgList = va_arg(ap, PrintfArguments*);
+    }
+    useIntern = bFlags & SQLITE_PRINTF_INTERNAL;
+  }else{
+    bArgList = useIntern = 0;
+  }
   for(; (c=(*fmt))!=0; ++fmt){
     if( c!='%' ){
       int amt;
@@ -238,7 +266,11 @@ void sqlite3VXPrintf(
     /* Get the field width */
     width = 0;
     if( c=='*' ){
-      width = va_arg(ap,int);
+      if( bArgList ){
+        width = (int)getIntArg(pArgList);
+      }else{
+        width = va_arg(ap,int);
+      }
       if( width<0 ){
         flag_leftjustify = 1;
         width = -width;
@@ -255,7 +287,11 @@ void sqlite3VXPrintf(
       precision = 0;
       c = *++fmt;
       if( c=='*' ){
-        precision = va_arg(ap,int);
+        if( bArgList ){
+          precision = (int)getIntArg(pArgList);
+        }else{
+          precision = va_arg(ap,int);
+        }
         if( precision<0 ) precision = -precision;
         c = *++fmt;
       }else{
@@ -286,7 +322,7 @@ void sqlite3VXPrintf(
     for(idx=0; idx<ArraySize(fmtinfo); idx++){
       if( c==fmtinfo[idx].fmttype ){
         infop = &fmtinfo[idx];
-        if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
+        if( useIntern || (infop->flags & FLAG_INTERN)==0 ){
           xtype = infop->type;
         }else{
           return;
@@ -326,7 +362,9 @@ void sqlite3VXPrintf(
       case etRADIX:
         if( infop->flags & FLAG_SIGNED ){
           i64 v;
-          if( flag_longlong ){
+          if( bArgList ){
+            v = getIntArg(pArgList);
+          }else if( flag_longlong ){
             v = va_arg(ap,i64);
           }else if( flag_long ){
             v = va_arg(ap,long int);
@@ -347,7 +385,9 @@ void sqlite3VXPrintf(
             else                       prefix = 0;
           }
         }else{
-          if( flag_longlong ){
+          if( bArgList ){
+            longvalue = (u64)getIntArg(pArgList);
+          }else if( flag_longlong ){
             longvalue = va_arg(ap,u64);
           }else if( flag_long ){
             longvalue = va_arg(ap,unsigned long int);
@@ -407,7 +447,11 @@ void sqlite3VXPrintf(
       case etFLOAT:
       case etEXP:
       case etGENERIC:
-        realvalue = va_arg(ap,double);
+        if( bArgList ){
+          realvalue = getDoubleArg(pArgList);
+        }else{
+          realvalue = va_arg(ap,double);
+        }
 #ifdef SQLITE_OMIT_FLOATING_POINT
         length = 0;
 #else
@@ -562,7 +606,7 @@ void sqlite3VXPrintf(
 #endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
         break;
       case etSIZE:
-        *(va_arg(ap,int*)) = pAccum->nChar;
+        if( !bArgList ) *(va_arg(ap,int*)) = pAccum->nChar;
         length = width = 0;
         break;
       case etPERCENT:
@@ -571,7 +615,11 @@ void sqlite3VXPrintf(
         length = 1;
         break;
       case etCHARX:
-        c = va_arg(ap,int);
+        if( bArgList ){
+          c = (int)getIntArg(pArgList);
+        }else{
+          c = va_arg(ap,int);
+        }
         buf[0] = (char)c;
         if( precision>=0 ){
           for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
@@ -583,10 +631,14 @@ void sqlite3VXPrintf(
         break;
       case etSTRING:
       case etDYNSTRING:
-        bufpt = va_arg(ap,char*);
+        if( bArgList ){
+          bufpt = getTextArg(pArgList);
+        }else{
+          bufpt = va_arg(ap,char*);
+        }
         if( bufpt==0 ){
           bufpt = "";
-        }else if( xtype==etDYNSTRING ){
+        }else if( xtype==etDYNSTRING && !bArgList ){
           zExtra = bufpt;
         }
         if( precision>=0 ){
@@ -602,7 +654,13 @@ void sqlite3VXPrintf(
         int needQuote;
         char ch;
         char q = ((xtype==etSQLESCAPE3)?'"':'\'');   /* Quote character */
-        char *escarg = va_arg(ap,char*);
+        char *escarg;
+
+        if( bArgList ){
+          escarg = getTextArg(pArgList);
+        }else{
+          escarg = va_arg(ap,char*);
+        }
         isnull = escarg==0;
         if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
         k = precision;
@@ -637,6 +695,7 @@ void sqlite3VXPrintf(
       }
       case etTOKEN: {
         Token *pToken = va_arg(ap, Token*);
+        assert( bArgList==0 );
         if( pToken && pToken->n ){
           sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
         }
@@ -647,6 +706,7 @@ void sqlite3VXPrintf(
         SrcList *pSrc = va_arg(ap, SrcList*);
         int k = va_arg(ap, int);
         struct SrcList_item *pItem = &pSrc->a[k];
+        assert( bArgList==0 );
         assert( k>=0 && k<pSrc->nSrc );
         if( pItem->zDatabase ){
           sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase);
@@ -810,7 +870,7 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
   sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
                       db->aLimit[SQLITE_LIMIT_LENGTH]);
   acc.db = db;
-  sqlite3VXPrintf(&acc, 1, zFormat, ap);
+  sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap);
   z = sqlite3StrAccumFinish(&acc);
   if( acc.accError==STRACCUM_NOMEM ){
     db->mallocFailed = 1;
@@ -966,14 +1026,12 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
 }
 #endif
 
-#ifndef SQLITE_OMIT_TRACE
 /*
 ** variable-argument wrapper around sqlite3VXPrintf().
 */
-void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
+void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){
   va_list ap;
   va_start(ap,zFormat);
-  sqlite3VXPrintf(p, 1, zFormat, ap);
+  sqlite3VXPrintf(p, bFlags, zFormat, ap);
   va_end(ap);
 }
-#endif
index 8e1436efd31e5a659e25ae47fe2a5862dc2212e8..af018edf01f75eb18f4cf8dfa731240545078dcd 100644 (file)
@@ -742,6 +742,7 @@ typedef struct LookasideSlot LookasideSlot;
 typedef struct Module Module;
 typedef struct NameContext NameContext;
 typedef struct Parse Parse;
+typedef struct PrintfArguments PrintfArguments;
 typedef struct RowSet RowSet;
 typedef struct Savepoint Savepoint;
 typedef struct Select Select;
@@ -2764,10 +2765,20 @@ void sqlite3StatusSet(int, int);
 # define sqlite3IsNaN(X)  0
 #endif
 
-void sqlite3VXPrintf(StrAccum*, int, const char*, va_list);
-#ifndef SQLITE_OMIT_TRACE
-void sqlite3XPrintf(StrAccum*, const char*, ...);
-#endif
+/*
+** An instance of the following structure holds information about SQL
+** functions arguments that are the parameters to the printf() function.
+*/
+struct PrintfArguments {
+  int nArg;                /* Total number of arguments */
+  int nUsed;               /* Number of arguments used so far */
+  sqlite3_value **apArg;   /* The argument values */
+};
+
+#define SQLITE_PRINTF_INTERNAL 0x01
+#define SQLITE_PRINTF_SQLFUNC  0x02
+void sqlite3VXPrintf(StrAccum*, u32, const char*, va_list);
+void sqlite3XPrintf(StrAccum*, u32, const char*, ...);
 char *sqlite3MPrintf(sqlite3*,const char*, ...);
 char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
 char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
index a7ff0a685d9b383f2f212bb06d44623949bb9394..4a39e26521d6af4cf92df1ea90043f68f7237df7 100644 (file)
@@ -125,9 +125,9 @@ char *sqlite3VdbeExpandSql(
       if( pVar->flags & MEM_Null ){
         sqlite3StrAccumAppend(&out, "NULL", 4);
       }else if( pVar->flags & MEM_Int ){
-        sqlite3XPrintf(&out, "%lld", pVar->u.i);
+        sqlite3XPrintf(&out, 0, "%lld", pVar->u.i);
       }else if( pVar->flags & MEM_Real ){
-        sqlite3XPrintf(&out, "%!.15g", pVar->r);
+        sqlite3XPrintf(&out, 0, "%!.15g", pVar->r);
       }else if( pVar->flags & MEM_Str ){
         int nOut;  /* Number of bytes of the string text to include in output */
 #ifndef SQLITE_OMIT_UTF16
@@ -148,15 +148,17 @@ char *sqlite3VdbeExpandSql(
           while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
         }
 #endif    
-        sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
+        sqlite3XPrintf(&out, 0, "'%.*q'", nOut, pVar->z);
 #ifdef SQLITE_TRACE_SIZE_LIMIT
-        if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+        if( nOut<pVar->n ){
+          sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
+        }
 #endif
 #ifndef SQLITE_OMIT_UTF16
         if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
 #endif
       }else if( pVar->flags & MEM_Zero ){
-        sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
+        sqlite3XPrintf(&out, 0, "zeroblob(%d)", pVar->u.nZero);
       }else{
         int nOut;  /* Number of bytes of the blob to include in output */
         assert( pVar->flags & MEM_Blob );
@@ -166,11 +168,13 @@ char *sqlite3VdbeExpandSql(
         if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
 #endif
         for(i=0; i<nOut; i++){
-          sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+          sqlite3XPrintf(&out, 0, "%02x", pVar->z[i]&0xff);
         }
         sqlite3StrAccumAppend(&out, "'", 1);
 #ifdef SQLITE_TRACE_SIZE_LIMIT
-        if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+        if( nOut<pVar->n ){
+          sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
+        }
 #endif
       }
     }
@@ -229,7 +233,7 @@ void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){
       sqlite3AppendSpace(&p->str, p->aIndent[n-1]);
     }   
     va_start(ap, zFormat);
-    sqlite3VXPrintf(&p->str, 1, zFormat, ap);
+    sqlite3VXPrintf(&p->str, SQLITE_PRINTF_INTERNAL, zFormat, ap);
     va_end(ap);
   }
 }
diff --git a/test/printf2.test b/test/printf2.test
new file mode 100644 (file)
index 0000000..6a017f1
--- /dev/null
@@ -0,0 +1,56 @@
+# 2013-12-17
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing the printf() SQL function.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_execsql_test printf2-1.1 {
+  SELECT printf();
+} {{}}
+do_execsql_test printf2-1.2 {
+  SELECT printf('hello');
+} {hello}
+do_execsql_test printf2-1.3 {
+  SELECT printf('%d,%d,%d',55,-11,3421);
+} {55,-11,3421}
+do_execsql_test printf2-1.4 {
+  SELECT printf('%d,%d,%d',55,'-11',3421);
+} {55,-11,3421}
+do_execsql_test printf2-1.5 {
+  SELECT printf('%d,%d,%d,%d',55,'-11',3421);
+} {55,-11,3421,0}
+do_execsql_test printf2-1.6 {
+  SELECT printf('%.2f',3.141592653);
+} {3.14}
+do_execsql_test printf2-1.7 {
+  SELECT printf('%.*f',2,3.141592653);
+} {3.14}
+do_execsql_test printf2-1.8 {
+  SELECT printf('%*.*f',5,2,3.141592653);
+} {{ 3.14}}
+do_execsql_test printf2-1.9 {
+  SELECT printf('%d',314159.2653);
+} {314159}
+do_execsql_test printf2-1.10 {
+  SELECT printf('%lld',314159.2653);
+} {314159}
+do_execsql_test printf2-1.11 {
+  SELECT printf('%lld%n',314159.2653,'hi');
+} {314159}
+do_execsql_test printf2-1.12 {
+  SELECT printf('%.*z',5,'abcdefghijklmnop');
+} {abcde}
+
+
+finish_test