} /* End of function */ /* ** Append N bytes of text from z to the StrAccum object. */ static void sqlite3StrAccumAppend( StrAccum p, string z, int N ) { Debug.Assert( z != null || N == 0 ); if ( p.tooBig )//|| p.mallocFailed != 0 ) { testcase( p.tooBig ); //testcase( p.mallocFailed ); return; } if ( N < 0 ) { N = sqlite3Strlen30( z ); } if ( N == 0 || NEVER( z == null ) ) { return; } //if( p->nChar+N >= p->nAlloc ){ // char *zNew; // if( !p->useMalloc ){ // p->tooBig = 1; // N = p->nAlloc - p->nChar - 1; // if( N<=0 ){ // return; // } // }else{ // char *zOld = (p->zText==p->zBase ? 0 : p->zText); // i64 szNew = p->nChar; // szNew += N + 1; // if( szNew > p->mxAlloc ){ // sqlite3StrAccumReset(p); // p->tooBig = 1; // return; // }else{ // p->nAlloc = (int)szNew; // } // if( p->useMalloc==1 ){ // zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); // }else{ // zNew = sqlite3_realloc(zOld, p->nAlloc); // } // if( zNew ){ // if( zOld==0 ) memcpy(zNew, p->zText, p->nChar); // p->zText = zNew; // }else{ // p->mallocFailed = 1; // sqlite3StrAccumReset(p); // return; // } // } //} //memcpy(&p->zText[p->nChar], z, N); p.zText.Append( z.Substring( 0, N <= z.Length ? N : z.Length ) ); //p.nChar += N; }
/* ** Finish off a string by making sure it is zero-terminated. ** Return a pointer to the resulting string. Return a NULL ** pointer if any kind of error was encountered. */ static string sqlite3StrAccumFinish( StrAccum p ) { //if ( p->zText ) //{ // p->zText[p->nChar] = 0; // if ( p->useMalloc && p->zText == p->zBase ) // { // if ( p->useMalloc == 1 ) // { // p->zText = sqlite3DbMallocRaw( p->db, p->nChar + 1 ); // } // else // { // p->zText = sqlite3_malloc( p->nChar + 1 ); // } // if ( p->zText ) // { // memcpy( p->zText, p->zBase, p->nChar + 1 ); // } // else // { // p->mallocFailed = 1; // } // } //} return p.zText.ToString(); }
} /* End of function */ /* ** Append N bytes of text from z to the StrAccum object. */ static void sqlite3StrAccumAppend( StrAccum p, string z, int N ) { Debug.Assert( z != null || N == 0 ); if ( p.tooBig != 0 )//|| p.mallocFailed != 0 ) { testcase( p.tooBig ); //testcase( p.mallocFailed ); return; } if ( N < 0 ) { N = sqlite3Strlen30( z ); } if ( N == 0 || NEVER( z == null ) ) { return; } //if ( p.nChar + N >= p.nAlloc ) //{ // char* zNew; // if ( !p.useMalloc ) // { // p.tooBig = 1; // N = p.nAlloc - p.nChar - 1; // if ( N <= 0 ) // { // return; // } // } // else // { // i64 szNew = p.nChar; // szNew += N + 1; // if ( szNew > p.mxAlloc ) // { // sqlite3StrAccumReset( p ); // p.tooBig = 1; // return; // } // else // { // p.nAlloc = (int)szNew; // } // zNew = sqlite3DbMalloc( p.nAlloc ); // if ( zNew ) // { // memcpy( zNew, p.zText, p.nChar ); // sqlite3StrAccumReset( p ); // p.zText = zNew; // } // else // { // p.mallocFailed = 1; // sqlite3StrAccumReset( p ); // return; // } // } //} //memcpy( &p.zText[p.nChar], z, N ); p.zText.Append( z.Substring( 0, N <= z.Length ? N : z.Length ) ); p.nChar += N; }
/* Make sure "isView" and other macros defined above are undefined. Otherwise ** thely may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ //#if isView // #undef isView //#endif //#if pTrigger // #undef pTrigger //#endif //#if tmask // #undef tmask //#endif /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** The input is a range of consecutive registers as follows: ** ** 1. The rowid of the row after the update. ** ** 2. The data in the first column of the entry after the update. ** ** i. Data from middle columns... ** ** N. The data in the last column of the entry after the update. ** ** The regRowid parameter is the index of the register containing (1). ** ** If isUpdate is true and rowidChng is non-zero, then rowidChng contains ** the address of a register containing the rowid before the update takes ** place. isUpdate is true for UPDATEs and false for INSERTs. If isUpdate ** is false, indicating an INSERT statement, then a non-zero rowidChng ** indicates that the rowid was explicitly specified as part of the ** INSERT statement. If rowidChng is false, it means that the rowid is ** computed automatically in an insert or that the rowid value is not ** modified by an update. ** ** The code generated by this routine store new index entries into ** registers identified by aRegIdx[]. No index entry is created for ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** the same as the order of indices on the linked list of indices ** attached to the table. ** ** This routine also generates code to check constraints. NOT NULL, ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, ** then the appropriate action is performed. There are five possible ** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. ** ** Constraint type Action What Happens ** --------------- ---------- ---------------------------------------- ** any ROLLBACK The current transaction is rolled back and ** sqlite3_exec() returns immediately with a ** return code of SQLITE_CONSTRAINT. ** ** any ABORT Back out changes from the current command ** only (do not do a complete rollback) then ** cause sqlite3_exec() to return immediately ** with SQLITE_CONSTRAINT. ** ** any FAIL Sqlite_exec() returns immediately with a ** return code of SQLITE_CONSTRAINT. The ** transaction is not rolled back and any ** prior changes are retained. ** ** any IGNORE The record number and data is popped from ** the stack and there is an immediate jump ** to label ignoreDest. ** ** NOT NULL REPLACE The NULL value is replace by the default ** value for that column. If the default value ** is NULL, the action is the same as ABORT. ** ** UNIQUE REPLACE The other row that conflicts with the row ** being inserted is removed. ** ** CHECK REPLACE Illegal. The results in an exception. ** ** Which action to take is determined by the overrideError parameter. ** Or if overrideError==OE_Default, then the pParse.onError parameter ** is used. Or if pParse.onError==OE_Default then the onError value ** for the constraint is used. ** ** The calling routine must open a read/write cursor for pTab with ** cursor number "baseCur". All indices of pTab must also have open ** read/write cursors with cursor number baseCur+i for the i-th cursor. ** Except, if there is no possibility of a REPLACE action then ** cursors do not need to be open for indices where aRegIdx[i]==0. */ static void sqlite3GenerateConstraintChecks( Parse pParse, /* The parser context */ Table pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Index of the range of input registers */ int[] aRegIdx, /* Register used by each index. 0 for unused indices */ int rowidChng, /* True if the rowid might collide with existing entry */ bool isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ out int pbMayReplace /* OUT: Set to true if constraint may cause a replace */ ) { int i; /* loop counter */ Vdbe v; /* VDBE under constrution */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index pIdx; /* Pointer to one of the indices */ bool seenReplace = false; /* True if REPLACE is used to resolve INT PK conflict */ int regOldRowid = ( rowidChng != 0 && isUpdate ) ? rowidChng : regRowid; v = sqlite3GetVdbe( pParse ); Debug.Assert( v != null ); Debug.Assert( pTab.pSelect == null ); /* This table is not a VIEW */ nCol = pTab.nCol; regData = regRowid + 1; /* Test all NOT NULL constraints. */ for ( i = 0; i < nCol; i++ ) { if ( i == pTab.iPKey ) { continue; } onError = pTab.aCol[i].notNull; if ( onError == OE_None ) continue; if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( onError == OE_Replace && pTab.aCol[i].pDflt == null ) { onError = OE_Abort; } Debug.Assert( onError == OE_Rollback || onError == OE_Abort || onError == OE_Fail || onError == OE_Ignore || onError == OE_Replace ); switch ( onError ) { case OE_Abort: { sqlite3MayAbort( pParse ); goto case OE_Fail; } case OE_Rollback: case OE_Fail: { string zMsg; sqlite3VdbeAddOp3( v, OP_HaltIfNull, SQLITE_CONSTRAINT, onError, regData + i ); zMsg = sqlite3MPrintf( pParse.db, "%s.%s may not be NULL", pTab.zName, pTab.aCol[i].zName ); sqlite3VdbeChangeP4( v, -1, zMsg, P4_DYNAMIC ); break; } case OE_Ignore: { sqlite3VdbeAddOp2( v, OP_IsNull, regData + i, ignoreDest ); break; } default: { Debug.Assert( onError == OE_Replace ); j1 = sqlite3VdbeAddOp1( v, OP_NotNull, regData + i ); sqlite3ExprCode( pParse, pTab.aCol[i].pDflt, regData + i ); sqlite3VdbeJumpHere( v, j1 ); break; } } } /* Test all CHECK constraints */ #if !SQLITE_OMIT_CHECK if ( pTab.pCheck != null && ( pParse.db.flags & SQLITE_IgnoreChecks ) == 0 ) { int allOk = sqlite3VdbeMakeLabel( v ); pParse.ckBase = regData; sqlite3ExprIfTrue( pParse, pTab.pCheck, allOk, SQLITE_JUMPIFNULL ); onError = overrideError != OE_Default ? overrideError : OE_Abort; if ( onError == OE_Ignore ) { sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); } else { if ( onError == OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ sqlite3HaltConstraint( pParse, onError, (string)null, 0 ); } sqlite3VdbeResolveLabel( v, allOk ); } #endif // * !SQLITE_OMIT_CHECK) */ /* If we have an INTEGER PRIMARY KEY, make sure the primary key ** of the new record does not previously exist. Except, if this ** is an UPDATE and the primary key is not changing, that is OK. */ if ( rowidChng != 0 ) { onError = pTab.keyConf; if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( isUpdate ) { j2 = sqlite3VdbeAddOp3( v, OP_Eq, regRowid, 0, rowidChng ); } j3 = sqlite3VdbeAddOp3( v, OP_NotExists, baseCur, 0, regRowid ); switch ( onError ) { default: { onError = OE_Abort; /* Fall thru into the next case */ } goto case OE_Rollback; case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3HaltConstraint( pParse, onError, "PRIMARY KEY must be unique", P4_STATIC ); break; } case OE_Replace: { /* If there are DELETE triggers on this table and the ** recursive-triggers flag is set, call GenerateRowDelete() to ** remove the conflicting row from the the table. This will fire ** the triggers and remove both the table and index b-tree entries. ** ** Otherwise, if there are no triggers or the recursive-triggers ** flag is not set, but the table has one or more indexes, call ** GenerateRowIndexDelete(). This removes the index b-tree entries ** only. The table b-tree entry will be replaced by the new entry ** when it is inserted. ** ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called, ** also invoke MultiWrite() to indicate that this VDBE may require ** statement rollback (if the statement is aborted after the delete ** takes place). Earlier versions called sqlite3MultiWrite() regardless, ** but being more selective here allows statements like: ** ** REPLACE INTO t(rowid) VALUES($newrowid) ** ** to run without a statement journal if there are no indexes on the ** table. */ Trigger pTrigger = null; if ( ( pParse.db.flags & SQLITE_RecTriggers ) != 0 ) { int iDummy; pTrigger = sqlite3TriggersExist( pParse, pTab, TK_DELETE, null, out iDummy ); } if ( pTrigger != null || sqlite3FkRequired( pParse, pTab, null, 0 ) != 0 ) { sqlite3MultiWrite( pParse ); sqlite3GenerateRowDelete( pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace ); } else if ( pTab.pIndex != null ) { sqlite3MultiWrite( pParse ); sqlite3GenerateRowIndexDelete( pParse, pTab, baseCur, 0 ); } seenReplace = true; break; } case OE_Ignore: { Debug.Assert( !seenReplace ); sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); break; } } sqlite3VdbeJumpHere( v, j3 ); if ( isUpdate ) { sqlite3VdbeJumpHere( v, j2 ); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ for ( iCur = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, iCur++ ) { int regIdx; int regR; if ( aRegIdx[iCur] == 0 ) continue; /* Skip unused indices */ /* Create a key for accessing the index entry */ regIdx = sqlite3GetTempRange( pParse, pIdx.nColumn + 1 ); for ( i = 0; i < pIdx.nColumn; i++ ) { int idx = pIdx.aiColumn[i]; if ( idx == pTab.iPKey ) { sqlite3VdbeAddOp2( v, OP_SCopy, regRowid, regIdx + i ); } else { sqlite3VdbeAddOp2( v, OP_SCopy, regData + idx, regIdx + i ); } } sqlite3VdbeAddOp2( v, OP_SCopy, regRowid, regIdx + i ); sqlite3VdbeAddOp3( v, OP_MakeRecord, regIdx, pIdx.nColumn + 1, aRegIdx[iCur] ); sqlite3VdbeChangeP4( v, -1, sqlite3IndexAffinityStr( v, pIdx ), P4_TRANSIENT ); sqlite3ExprCacheAffinityChange( pParse, regIdx, pIdx.nColumn + 1 ); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx.onError; if ( onError == OE_None ) { sqlite3ReleaseTempRange( pParse, regIdx, pIdx.nColumn + 1 ); continue; /* pIdx is not a UNIQUE index */ } if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( seenReplace ) { if ( onError == OE_Ignore ) onError = OE_Replace; else if ( onError == OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ regR = sqlite3GetTempReg( pParse ); sqlite3VdbeAddOp2( v, OP_SCopy, regOldRowid, regR ); j3 = sqlite3VdbeAddOp4( v, OP_IsUnique, baseCur + iCur + 1, 0, regR, regIdx,//regR, SQLITE_INT_TO_PTR(regIdx), P4_INT32 ); sqlite3ReleaseTempRange( pParse, regIdx, pIdx.nColumn + 1 ); /* Generate code that executes if the new index entry is not unique */ Debug.Assert( onError == OE_Rollback || onError == OE_Abort || onError == OE_Fail || onError == OE_Ignore || onError == OE_Replace ); switch ( onError ) { case OE_Rollback: case OE_Abort: case OE_Fail: { int j; StrAccum errMsg = new StrAccum( 200 ); string zSep; string zErr; sqlite3StrAccumInit( errMsg, null, 0, 200 ); errMsg.db = pParse.db; zSep = pIdx.nColumn > 1 ? "columns " : "column "; for ( j = 0; j < pIdx.nColumn; j++ ) { string zCol = pTab.aCol[pIdx.aiColumn[j]].zName; sqlite3StrAccumAppend( errMsg, zSep, -1 ); zSep = ", "; sqlite3StrAccumAppend( errMsg, zCol, -1 ); } sqlite3StrAccumAppend( errMsg, pIdx.nColumn > 1 ? " are not unique" : " is not unique", -1 ); zErr = sqlite3StrAccumFinish( errMsg ); sqlite3HaltConstraint( pParse, onError, zErr, 0 ); sqlite3DbFree( errMsg.db, ref zErr ); break; } case OE_Ignore: { Debug.Assert( !seenReplace ); sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); break; } default: { Trigger pTrigger = null; Debug.Assert( onError == OE_Replace ); sqlite3MultiWrite( pParse ); if ( ( pParse.db.flags & SQLITE_RecTriggers ) != 0 ) { int iDummy; pTrigger = sqlite3TriggersExist( pParse, pTab, TK_DELETE, null, out iDummy ); } sqlite3GenerateRowDelete( pParse, pTab, baseCur, regR, 0, pTrigger, OE_Replace ); seenReplace = true; break; } } sqlite3VdbeJumpHere( v, j3 ); sqlite3ReleaseTempReg( pParse, regR ); } //if ( pbMayReplace ) { pbMayReplace = seenReplace ? 1 : 0; } }
static char[] buf = new char[etBUFSIZE]; /* Conversion buffer */ static void sqlite3VXPrintf( StrAccum pAccum, /* Accumulate results here */ int useExtended, /* Allow extended %-conversions */ string fmt, /* Format string */ va_list[] ap /* arguments */ ) { int c; /* Next character in the format string */ int bufpt; /* Pointer to the conversion buffer */ int precision; /* Precision of the current field */ int length; /* Length of the field */ int idx; /* A general purpose loop counter */ int width; /* Width of the current field */ etByte flag_leftjustify; /* True if "-" flag is present */ etByte flag_plussign; /* True if "+" flag is present */ etByte flag_blanksign; /* True if " " flag is present */ etByte flag_alternateform; /* True if "#" flag is present */ etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ etByte done; /* Loop termination flag */ i64 longvalue; LONGDOUBLE_TYPE realvalue; /* Value for real types */ et_info infop; /* Pointer to the appropriate info structure */ char[] buf = new char[etBUFSIZE]; /* Conversion buffer */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ byte xtype = 0; /* Conversion paradigm */ // Not used in C# -- string zExtra; /* Extra memory used for etTCLESCAPE conversions */ #if !SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ etByte flag_exp; /* True to force display of the exponent */ int nsd; /* Number of significant digits returned */ #endif length = 0; bufpt = 0; int _fmt = 0; // Work around string pointer fmt += '\0'; for ( ; _fmt <= fmt.Length && ( c = fmt[_fmt] ) != 0; ++_fmt ) { if ( c != '%' ) { int amt; bufpt = _fmt; amt = 1; while ( _fmt < fmt.Length && ( c = ( fmt[++_fmt] ) ) != '%' && c != 0 ) amt++; sqlite3StrAccumAppend( pAccum, fmt.Substring( bufpt, amt ), amt ); if ( c == 0 ) break; } if ( _fmt < fmt.Length && ( c = ( fmt[++_fmt] ) ) == 0 ) { sqlite3StrAccumAppend( pAccum, "%", 1 ); break; } /* Find out what flags are present */ flag_leftjustify = flag_plussign = flag_blanksign = flag_alternateform = flag_altform2 = flag_zeropad = false; done = false; do { switch ( c ) { case '-': flag_leftjustify = true; break; case '+': flag_plussign = true; break; case ' ': flag_blanksign = true; break; case '#': flag_alternateform = true; break; case '!': flag_altform2 = true; break; case '0': flag_zeropad = true; break; default: done = true; break; } } while ( !done && _fmt < fmt.Length - 1 && ( c = ( fmt[++_fmt] ) ) != 0 ); /* Get the field width */ width = 0; if ( c == '*' ) { width = (int)va_arg( ap, "int" ); if ( width < 0 ) { flag_leftjustify = true; width = -width; } c = fmt[++_fmt]; } else { while ( c >= '0' && c <= '9' ) { width = width * 10 + c - '0'; c = fmt[++_fmt]; } } if ( width > etBUFSIZE - 10 ) { width = etBUFSIZE - 12; } /* Get the precision */ if ( c == '.' ) { precision = 0; c = fmt[++_fmt]; if ( c == '*' ) { precision = (int)va_arg( ap, "int" ); if ( precision < 0 ) precision = -precision; c = fmt[++_fmt]; } else { while ( c >= '0' && c <= '9' ) { precision = precision * 10 + c - '0'; c = fmt[++_fmt]; } } } else { precision = -1; } /* Get the conversion type modifier */ if ( c == 'l' ) { flag_long = true; c = fmt[++_fmt]; if ( c == 'l' ) { flag_longlong = true; c = fmt[++_fmt]; } else { flag_longlong = false; } } else { flag_long = flag_longlong = false; } /* Fetch the info entry for the field */ infop = fmtinfo[0]; xtype = etINVALID; for ( idx = 0; idx < ArraySize( fmtinfo ); idx++ ) { if ( c == fmtinfo[idx].fmttype ) { infop = fmtinfo[idx]; if ( useExtended != 0 || ( infop.flags & FLAG_INTERN ) == 0 ) { xtype = infop.type; } else { return; } break; } } //zExtra = null; /* Limit the precision to prevent overflowing buf[] during conversion */ if ( precision > etBUFSIZE - 40 && ( infop.flags & FLAG_STRING ) == 0 ) { precision = etBUFSIZE - 40; } /* ** At this point, variables are initialized as follows: ** ** flag_alternateform TRUE if a '#' is present. ** flag_altform2 TRUE if a '!' is present. ** flag_plussign TRUE if a '+' is present. ** flag_leftjustify TRUE if a '-' is present or if the ** field width was negative. ** flag_zeropad TRUE if the width began with 0. ** flag_long TRUE if the letter 'l' (ell) prefixed ** the conversion character. ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed ** the conversion character. ** flag_blanksign TRUE if a ' ' is present. ** width The specified field width. This is ** always non-negative. Zero is the default. ** precision The specified precision. The default ** is -1. ** xtype The class of the conversion. ** infop Pointer to the appropriate info struct. */ switch ( xtype ) { case etPOINTER: flag_longlong = true;// char*.Length == sizeof(i64); flag_long = false;// char*.Length == sizeof(long); /* Fall through into the next case */ goto case etRADIX; case etORDINAL: case etRADIX: if ( ( infop.flags & FLAG_SIGNED ) != 0 ) { i64 v; if ( flag_longlong ) { v = (long)va_arg( ap, "i64" ); } else if ( flag_long ) { v = (long)va_arg( ap, "long int" ); } else { v = (int)va_arg( ap, "int" ); } if ( v < 0 ) { longvalue = -v; prefix = '-'; } else { longvalue = v; if ( flag_plussign ) prefix = '+'; else if ( flag_blanksign ) prefix = ' '; else prefix = '\0'; } } else { if ( flag_longlong ) { longvalue = (i64)va_arg( ap, "longlong int" ); } else if ( flag_long ) { longvalue = (i64)va_arg( ap, "long int" ); } else { longvalue = (i64)va_arg( ap, "long" ); } prefix = '\0'; } if ( longvalue == 0 ) flag_alternateform = false; if ( flag_zeropad && precision < width - ( ( prefix != '\0' ) ? 1 : 0 ) ) { precision = width - ( ( prefix != '\0' ) ? 1 : 0 ); } bufpt = buf.Length;//[etBUFSIZE-1]; char[] _bufOrd = null; if ( xtype == etORDINAL ) { char[] zOrd = "thstndrd".ToCharArray(); int x = (int)( longvalue % 10 ); if ( x >= 4 || ( longvalue / 10 ) % 10 == 1 ) { x = 0; } _bufOrd = new char[2]; _bufOrd[0] = zOrd[x * 2]; _bufOrd[1] = zOrd[x * 2 + 1]; //bufpt -= 2; } { char[] _buf; switch ( infop._base ) { case 16: _buf = longvalue.ToString( "x" ).ToCharArray(); break; case 8: _buf = Convert.ToString( (long)longvalue, 8 ).ToCharArray(); break; default: { if ( flag_zeropad ) _buf = longvalue.ToString( new string( '0', width - ( ( prefix != '\0' ) ? 1 : 0 ) ) ).ToCharArray(); else _buf = longvalue.ToString().ToCharArray(); } break; } bufpt = buf.Length - _buf.Length - ( _bufOrd == null ? 0 : 2 ); Array.Copy( _buf, 0, buf, bufpt, _buf.Length ); if ( _bufOrd != null ) { buf[buf.Length - 1] = _bufOrd[1]; buf[buf.Length - 2] = _bufOrd[0]; } //char* cset; /* Use registers for speed */ //int _base; //cset = aDigits[infop.charset]; //_base = infop._base; //do //{ /* Convert to ascii */ // *(--bufpt) = cset[longvalue % (ulong)_base]; // longvalue = longvalue / (ulong)_base; //} while (longvalue > 0); } length = buf.Length - bufpt;//length = (int)(&buf[etBUFSIZE-1]-bufpt); for ( idx = precision - length; idx > 0; idx-- ) { buf[( --bufpt )] = '0'; /* Zero pad */ } if ( prefix != '\0' ) buf[--bufpt] = prefix; /* Add sign */ if ( flag_alternateform && infop.prefix != 0 ) { /* Add "0" or "0x" */ int pre; char x; pre = infop.prefix; for ( ; ( x = aPrefix[pre] ) != 0; pre++ ) buf[--bufpt] = x; } length = buf.Length - bufpt;//length = (int)(&buf[etBUFSIZE-1]-bufpt); break; case etFLOAT: case etEXP: case etGENERIC: realvalue = (double)va_arg( ap, "double" ); #if SQLITE_OMIT_FLOATING_POINT length = 0; #else if ( precision < 0 ) precision = 6; /* Set default precision */ if ( precision > etBUFSIZE / 2 - 10 ) precision = etBUFSIZE / 2 - 10; if ( realvalue < 0.0 ) { realvalue = -realvalue; prefix = '-'; } else { if ( flag_plussign ) prefix = '+'; else if ( flag_blanksign ) prefix = ' '; else prefix = '\0'; } if ( xtype == etGENERIC && precision > 0 ) precision--; #if FALSE /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); #else /* It makes more sense to use 0.5 */ for ( idx = precision, rounder = 0.5; idx > 0; idx--, rounder *= 0.1 ) { } #endif if ( xtype == etFLOAT ) realvalue += rounder; /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; double d = 0; if ( Double.IsNaN( realvalue ) || !( Double.TryParse( Convert.ToString( realvalue ), out d ) ) )//if( sqlite3IsNaN((double)realvalue) ) { buf[0] = 'N'; buf[1] = 'a'; buf[2] = 'N';// "NaN" length = 3; break; } if ( realvalue > 0.0 ) { while ( realvalue >= 1e32 && exp <= 350 ) { realvalue *= 1e-32; exp += 32; } while ( realvalue >= 1e8 && exp <= 350 ) { realvalue *= 1e-8; exp += 8; } while ( realvalue >= 10.0 && exp <= 350 ) { realvalue *= 0.1; exp++; } while ( realvalue < 1e-8 ) { realvalue *= 1e8; exp -= 8; } while ( realvalue < 1.0 ) { realvalue *= 10.0; exp--; } if ( exp > 350 ) { if ( prefix == '-' ) { buf[0] = '-'; buf[1] = 'I'; buf[2] = 'n'; buf[3] = 'f';// "-Inf" bufpt = 4; } else if ( prefix == '+' ) { buf[0] = '+'; buf[1] = 'I'; buf[2] = 'n'; buf[3] = 'f';// "+Inf" bufpt = 4; } else { buf[0] = 'I'; buf[1] = 'n'; buf[2] = 'f';// "Inf" bufpt = 3; } length = sqlite3Strlen30( bufpt );// sqlite3Strlen30(bufpt); bufpt = 0; break; } } bufpt = 0; /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ flag_exp = xtype == etEXP; if ( xtype != etFLOAT ) { realvalue += rounder; if ( realvalue >= 10.0 ) { realvalue *= 0.1; exp++; } } if ( xtype == etGENERIC ) { flag_rtz = !flag_alternateform; if ( exp < -4 || exp > precision ) { xtype = etEXP; } else { precision = precision - exp; xtype = etFLOAT; } } else { flag_rtz = false; } if ( xtype == etEXP ) { e2 = 0; } else { e2 = exp; } nsd = 0; flag_dp = ( precision > 0 ? true : false ) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if ( prefix != '\0' ) { buf[bufpt++] = prefix; } /* Digits prior to the decimal point */ if ( e2 < 0 ) { buf[bufpt++] = '0'; } else { for ( ; e2 >= 0; e2-- ) { buf[bufpt++] = (char)( et_getdigit( ref realvalue, ref nsd ) + '0' ); // *(bufpt++) = et_getdigit(ref realvalue, ref nsd); } } /* The decimal point */ if ( flag_dp ) { buf[bufpt++] = '.'; } /* "0" digits after the decimal point but before the first ** significant digit of the number */ for ( e2++; e2 < 0; precision--, e2++ ) { Debug.Assert( precision > 0 ); buf[bufpt++] = '0'; } /* Significant digits after the decimal point */ while ( ( precision-- ) > 0 ) { buf[bufpt++] = (char)( et_getdigit( ref realvalue, ref nsd ) + '0' ); // *(bufpt++) = et_getdigit(&realvalue, nsd); } /* Remove trailing zeros and the "." if no digits follow the "." */ if ( flag_rtz && flag_dp ) { while ( buf[bufpt - 1] == '0' ) buf[--bufpt] = '\0'; Debug.Assert( bufpt > 0 ); if ( buf[bufpt - 1] == '.' ) { if ( flag_altform2 ) { buf[( bufpt++ )] = '0'; } else { buf[( --bufpt )] = '0'; } } } /* Add the "eNNN" suffix */ if ( flag_exp || xtype == etEXP ) { buf[bufpt++] = aDigits[infop.charset]; if ( exp < 0 ) { buf[bufpt++] = '-'; exp = -exp; } else { buf[bufpt++] = '+'; } if ( exp >= 100 ) { buf[bufpt++] = (char)( exp / 100 + '0' ); /* 100's digit */ exp %= 100; } buf[bufpt++] = (char)( exp / 10 + '0' ); /* 10's digit */ buf[bufpt++] = (char)( exp % 10 + '0' ); /* 1's digit */ } //bufpt = 0; /* The converted number is in buf[] and zero terminated. Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions. */ length = bufpt;//length = (int)(bufpt-buf); bufpt = 0; /* Special case: Add leading zeros if the flag_zeropad flag is ** set and we are not left justified */ if ( flag_zeropad && !flag_leftjustify && length < width ) { int i; int nPad = width - length; for ( i = width; i >= nPad; i-- ) { buf[bufpt + i] = buf[bufpt + i - nPad]; } i = ( prefix != '\0' ? 1 : 0 ); while ( nPad-- != 0 ) buf[( bufpt++ ) + i] = '0'; length = width; bufpt = 0; } #endif //* !defined(SQLITE_OMIT_FLOATING_POINT) */ break; case etSIZE: ap[0] = pAccum.nChar; // *(va_arg(ap,int*)) = pAccum.nChar; length = width = 0; break; case etPERCENT: buf[0] = '%'; bufpt = 0; length = 1; break; case etCHARX: c = (char)va_arg( ap, "char" ); buf[0] = (char)c; if ( precision >= 0 ) { for ( idx = 1; idx < precision; idx++ ) buf[idx] = (char)c; length = precision; } else { length = 1; } bufpt = 0; break; case etSTRING: case etDYNSTRING: bufpt = 0;// string bufStr = (string)va_arg( ap, "string" ); if ( bufStr.Length > buf.Length ) buf = new char[bufStr.Length]; bufStr.ToCharArray().CopyTo( buf, 0 ); bufpt = bufStr.Length; if ( bufpt == 0 ) { buf[0] = '\0'; } else if ( xtype == etDYNSTRING ) { // zExtra = bufpt; } if ( precision >= 0 ) { for ( length = 0; length < precision && length < bufStr.Length && buf[length] != 0; length++ ) { } //length += precision; } else { length = sqlite3Strlen30( bufpt ); } bufpt = 0; break; case etSQLESCAPE: case etSQLESCAPE2: case etSQLESCAPE3: { int i; int j; int k; int n; bool isnull; bool needQuote; char ch; char q = ( ( xtype == etSQLESCAPE3 ) ? '"' : '\'' ); /* Quote character */ string escarg = (string)va_arg( ap, "char*" ) + '\0'; isnull = ( escarg == "" || escarg == "NULL\0" ); if ( isnull ) escarg = ( xtype == etSQLESCAPE2 ) ? "NULL\0" : "(NULL)\0"; k = precision; for ( i = n = 0; k != 0 && ( ch = escarg[i] ) != 0; i++, k-- ) { if ( ch == q ) n++; } needQuote = !isnull && ( xtype == etSQLESCAPE2 ); n += i + 1 + ( needQuote ? 2 : 0 ); if ( n > etBUFSIZE ) { buf = new char[n];//bufpt = zExtra = sqlite3Malloc(n); //if ( bufpt == 0 ) //{ // pAccum->mallocFailed = 1; // return; //} bufpt = 0; //Start of Buffer } else { //bufpt = buf; bufpt = 0; //Start of Buffer } j = 0; if ( needQuote ) buf[bufpt + j++] = q; k = i; for ( i = 0; i < k; i++ ) { buf[bufpt + j++] = ch = escarg[i]; if ( ch == q ) buf[bufpt + j++] = ch; } if ( needQuote ) buf[bufpt + j++] = q; buf[bufpt + j] = '\0'; length = j; /* The precision in %q and %Q means how many input characters to ** consume, not the length of the output... ** if( precision>=0 && precision<length ) length = precision; */ break; } case etTOKEN: { Token pToken = (Token)va_arg( ap, "Token" ); if ( pToken != null ) { sqlite3StrAccumAppend( pAccum, pToken.z.ToString(), (int)pToken.n ); } length = width = 0; break; } case etSRCLIST: { SrcList pSrc = (SrcList)va_arg( ap, "SrcList" ); int k = (int)va_arg( ap, "int" ); SrcList_item pItem = pSrc.a[k]; Debug.Assert( k >= 0 && k < pSrc.nSrc ); if ( pItem.zDatabase != null ) { sqlite3StrAccumAppend( pAccum, pItem.zDatabase, -1 ); sqlite3StrAccumAppend( pAccum, ".", 1 ); } sqlite3StrAccumAppend( pAccum, pItem.zName, -1 ); length = width = 0; break; } default: { Debug.Assert( xtype == etINVALID ); return; } }/* End switch over the format type */ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do ** the output. */ if ( !flag_leftjustify ) { int nspace; nspace = width - length;// -2; if ( nspace > 0 ) { appendSpace( pAccum, nspace ); } } if ( length > 0 ) { sqlite3StrAccumAppend( pAccum, new string( buf, bufpt, length ), length ); } if ( flag_leftjustify ) { int nspace; nspace = width - length; if ( nspace > 0 ) { appendSpace( pAccum, nspace ); } } //if( zExtra ){ // sqlite3DbFree(db,ref zExtra); //} }/* End for loop over the format string */ } /* End of function */
/* ** Initialize a string accumulator */ static void sqlite3StrAccumInit( StrAccum p, StringBuilder zBase, int n, int mx ) { p.zText = p.zBase = zBase; p.db = null; p.nChar = 0; p.nAlloc = n; p.mxAlloc = mx; p.useMalloc = 1; p.tooBig = 0; //p.mallocFailed = 0; }
/* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** The input is a range of consecutive registers as follows: ** ** 1. The rowid of the row to be updated before the update. This ** value is omitted unless we are doing an UPDATE that involves a ** change to the record number or writing to a virtual table. ** ** 2. The rowid of the row after the update. ** ** 3. The data in the first column of the entry after the update. ** ** i. Data from middle columns... ** ** N. The data in the last column of the entry after the update. ** ** The regRowid parameter is the index of the register containing (2). ** ** The old rowid shown as entry (1) above is omitted unless both isUpdate ** and rowidChng are 1. isUpdate is true for UPDATEs and false for ** INSERTs. RowidChng means that the new rowid is explicitly specified by ** the update or insert statement. If rowidChng is false, it means that ** the rowid is computed automatically in an insert or that the rowid value ** is not modified by the update. ** ** The code generated by this routine store new index entries into ** registers identified by aRegIdx[]. No index entry is created for ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** the same as the order of indices on the linked list of indices ** attached to the table. ** ** This routine also generates code to check constraints. NOT NULL, ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, ** then the appropriate action is performed. There are five possible ** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. ** ** Constraint type Action What Happens ** --------------- ---------- ---------------------------------------- ** any ROLLBACK The current transaction is rolled back and ** sqlite3_exec() returns immediately with a ** return code of SQLITE_CONSTRAINT. ** ** any ABORT Back out changes from the current command ** only (do not do a complete rollback) then ** cause sqlite3_exec() to return immediately ** with SQLITE_CONSTRAINT. ** ** any FAIL Sqlite_exec() returns immediately with a ** return code of SQLITE_CONSTRAINT. The ** transaction is not rolled back and any ** prior changes are retained. ** ** any IGNORE The record number and data is popped from ** the stack and there is an immediate jump ** to label ignoreDest. ** ** NOT NULL REPLACE The NULL value is replace by the default ** value for that column. If the default value ** is NULL, the action is the same as ABORT. ** ** UNIQUE REPLACE The other row that conflicts with the row ** being inserted is removed. ** ** CHECK REPLACE Illegal. The results in an exception. ** ** Which action to take is determined by the overrideError parameter. ** Or if overrideError==OE_Default, then the pParse.onError parameter ** is used. Or if pParse.onError==OE_Default then the onError value ** for the constraint is used. ** ** The calling routine must open a read/write cursor for pTab with ** cursor number "baseCur". All indices of pTab must also have open ** read/write cursors with cursor number baseCur+i for the i-th cursor. ** Except, if there is no possibility of a REPLACE action then ** cursors do not need to be open for indices where aRegIdx[i]==0. */ static void sqlite3GenerateConstraintChecks( Parse pParse, /* The parser context */ Table pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Index of the range of input registers */ int[] aRegIdx, /* Register used by each index. 0 for unused indices */ bool rowidChng, /* True if the rowid might collide with existing entry */ bool isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ ref int pbMayReplace /* OUT: Set to true if constraint may cause a replace */ ) { int i; /* loop counter */ Vdbe v; /* VDBE under constrution */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index pIdx; /* Pointer to one of the indices */ bool seenReplace = false; /* True if REPLACE is used to resolve INT PK conflict */ bool hasTwoRowids = ( isUpdate && rowidChng ); v = sqlite3GetVdbe( pParse ); Debug.Assert( v != null ); Debug.Assert( pTab.pSelect == null ); /* This table is not a VIEW */ nCol = pTab.nCol; regData = regRowid + 1; /* Test all NOT NULL constraints. */ for ( i = 0 ; i < nCol ; i++ ) { if ( i == pTab.iPKey ) { continue; } onError = pTab.aCol[i].notNull; if ( onError == OE_None ) continue; if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( onError == OE_Replace && pTab.aCol[i].pDflt == null ) { onError = OE_Abort; } Debug.Assert( onError == OE_Rollback || onError == OE_Abort || onError == OE_Fail || onError == OE_Ignore || onError == OE_Replace ); switch ( onError ) { case OE_Rollback: case OE_Abort: case OE_Fail: { string zMsg; j1 = sqlite3VdbeAddOp3( v, OP_HaltIfNull, SQLITE_CONSTRAINT, onError, regData + i ); zMsg = sqlite3MPrintf( pParse.db, "%s.%s may not be NULL", pTab.zName, pTab.aCol[i].zName ); sqlite3VdbeChangeP4( v, -1, zMsg, P4_DYNAMIC ); break; } case OE_Ignore: { sqlite3VdbeAddOp2( v, OP_IsNull, regData + i, ignoreDest ); break; } default: { Debug.Assert( onError == OE_Replace ); j1 = sqlite3VdbeAddOp1( v, OP_NotNull, regData + i ); sqlite3ExprCode( pParse, pTab.aCol[i].pDflt, regData + i ); sqlite3VdbeJumpHere( v, j1 ); break; } } } /* Test all CHECK constraints */ #if !SQLITE_OMIT_CHECK if ( pTab.pCheck != null && ( pParse.db.flags & SQLITE_IgnoreChecks ) == 0 ) { int allOk = sqlite3VdbeMakeLabel( v ); pParse.ckBase = regData; sqlite3ExprIfTrue( pParse, pTab.pCheck, allOk, SQLITE_JUMPIFNULL ); onError = overrideError != OE_Default ? overrideError : OE_Abort; if ( onError == OE_Ignore ) { sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); } else { sqlite3VdbeAddOp2( v, OP_Halt, SQLITE_CONSTRAINT, onError ); } sqlite3VdbeResolveLabel( v, allOk ); } #endif // * !SQLITE_OMIT_CHECK) */ /* If we have an INTEGER PRIMARY KEY, make sure the primary key ** of the new record does not previously exist. Except, if this ** is an UPDATE and the primary key is not changing, that is OK. */ if ( rowidChng ) { onError = pTab.keyConf; if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( onError != OE_Replace || pTab.pIndex != null ) { if ( isUpdate ) { j2 = sqlite3VdbeAddOp3( v, OP_Eq, regRowid, 0, regRowid - 1 ); } j3 = sqlite3VdbeAddOp3( v, OP_NotExists, baseCur, 0, regRowid ); switch ( onError ) { default: { onError = OE_Abort; /* Fall thru into the next case */ } goto case OE_Rollback; case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, "PRIMARY KEY must be unique", P4_STATIC ); break; } case OE_Replace: { sqlite3GenerateRowIndexDelete( pParse, pTab, baseCur, 0 ); seenReplace = true; break; } case OE_Ignore: { Debug.Assert( !seenReplace ); sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); break; } } sqlite3VdbeJumpHere( v, j3 ); if ( isUpdate ) { sqlite3VdbeJumpHere( v, j2 ); } } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ for ( iCur = 0, pIdx = pTab.pIndex ; pIdx != null ; pIdx = pIdx.pNext, iCur++ ) { int regIdx; int regR; if ( aRegIdx[iCur] == 0 ) continue; /* Skip unused indices */ /* Create a key for accessing the index entry */ regIdx = sqlite3GetTempRange( pParse, pIdx.nColumn + 1 ); for ( i = 0 ; i < pIdx.nColumn ; i++ ) { int idx = pIdx.aiColumn[i]; if ( idx == pTab.iPKey ) { sqlite3VdbeAddOp2( v, OP_SCopy, regRowid, regIdx + i ); } else { sqlite3VdbeAddOp2( v, OP_SCopy, regData + idx, regIdx + i ); } } sqlite3VdbeAddOp2( v, OP_SCopy, regRowid, regIdx + i ); sqlite3VdbeAddOp3( v, OP_MakeRecord, regIdx, pIdx.nColumn + 1, aRegIdx[iCur] ); sqlite3IndexAffinityStr( v, pIdx ); sqlite3ExprCacheAffinityChange( pParse, regIdx, pIdx.nColumn + 1 ); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx.onError; if ( onError == OE_None ) { sqlite3ReleaseTempRange( pParse, regIdx, pIdx.nColumn + 1 ); continue; /* pIdx is not a UNIQUE index */ } if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( seenReplace ) { if ( onError == OE_Ignore ) onError = OE_Replace; else if ( onError == OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ regR = sqlite3GetTempReg( pParse ); sqlite3VdbeAddOp2( v, OP_SCopy, regRowid - ( hasTwoRowids ? 1 : 0 ), regR ); j3 = sqlite3VdbeAddOp4( v, OP_IsUnique, baseCur + iCur + 1, 0, regR, regIdx,//regR, SQLITE_INT_TO_PTR(regIdx), P4_INT32 ); sqlite3ReleaseTempRange( pParse, regIdx, pIdx.nColumn + 1 ); /* Generate code that executes if the new index entry is not unique */ Debug.Assert( onError == OE_Rollback || onError == OE_Abort || onError == OE_Fail || onError == OE_Ignore || onError == OE_Replace ); switch ( onError ) { case OE_Rollback: case OE_Abort: case OE_Fail: { int j; StrAccum errMsg = new StrAccum(); string zSep; string zErr; sqlite3StrAccumInit( errMsg, new StringBuilder( 200 ), 0, 200 ); errMsg.db = pParse.db; zSep = pIdx.nColumn > 1 ? "columns " : "column "; for ( j = 0 ; j < pIdx.nColumn ; j++ ) { string zCol = pTab.aCol[pIdx.aiColumn[j]].zName; sqlite3StrAccumAppend( errMsg, zSep, -1 ); zSep = ", "; sqlite3StrAccumAppend( errMsg, zCol, -1 ); } sqlite3StrAccumAppend( errMsg, pIdx.nColumn > 1 ? " are not unique" : " is not unique", -1 ); zErr = sqlite3StrAccumFinish( errMsg ); sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, zErr, 0 ); //sqlite3DbFree( errMsg.db, zErr ); break; } case OE_Ignore: { Debug.Assert( !seenReplace ); sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); break; } default: { Debug.Assert( onError == OE_Replace ); sqlite3GenerateRowDelete( pParse, pTab, baseCur, regR, 0 ); seenReplace = true; break; } } sqlite3VdbeJumpHere( v, j3 ); sqlite3ReleaseTempReg( pParse, regR ); } //if ( pbMayReplace ) { pbMayReplace = seenReplace ? 1 : 0; } }
/* ** variable-argument wrapper around sqlite3VXPrintf(). */ static void sqlite3XPrintf( StrAccum p, string zFormat, params object[] ap ) { //va_list ap; lock ( lock_va_list ) { va_start( ap, zFormat ); sqlite3VXPrintf( p, 1, zFormat, ap ); va_end( ref ap ); } }
static public string sqlite3_snprintf( int n, ref string zBuf, string zFormat, params va_list[] ap ) { string z; StringBuilder zBase = new StringBuilder( SQLITE_PRINT_BUF_SIZE ); //va_list ap; StrAccum acc = new StrAccum(); if ( n <= 0 ) { return zBuf; } sqlite3StrAccumInit( acc, zBase, n, 0 ); acc.useMalloc = 0; va_start( ap, zFormat ); sqlite3VXPrintf( acc, 0, zFormat, ap ); va_end( ap ); z = sqlite3StrAccumFinish( acc ); return ( zBuf = z ); }
/* ** A version of printf() that understands %lld. Used for debugging. ** The printf() built into some versions of windows does not understand %lld ** and segfaults if you give it a long long int. */ static void sqlite3DebugPrintf( string zFormat, params va_list[] ap ) { //va_list ap; StrAccum acc = new StrAccum(); StringBuilder zBuf = new StringBuilder( SQLITE_PRINT_BUF_SIZE ); sqlite3StrAccumInit( acc, zBuf, zBuf.Capacity, 0 ); acc.useMalloc = 0; va_start( ap, zFormat ); sqlite3VXPrintf( acc, 0, zFormat, ap ); va_end( ap ); sqlite3StrAccumFinish( acc ); Console.Write( zBuf.ToString() ); //fflush(stdout); }
/* ** sqlite3_snprintf() works like snprintf() except that it ignores the ** current locale settings. This is important for SQLite because we ** are not able to use a "," as the decimal point in place of "." as ** specified by some locales. */ static public string sqlite3_snprintf( int n, ref StringBuilder zBuf, string zFormat, params va_list[] ap ) { StringBuilder zBase = new StringBuilder( SQLITE_PRINT_BUF_SIZE ); //va_list ap; StrAccum acc = new StrAccum(); if ( n <= 0 ) { return zBuf.ToString(); } sqlite3StrAccumInit( acc, zBase, n, 0 ); acc.useMalloc = 0; va_start( ap, zFormat ); sqlite3VXPrintf( acc, 0, zFormat, ap ); va_end( ap ); zBuf.Length = 0; zBuf.Append( sqlite3StrAccumFinish( acc ) ); if ( n - 1 < zBuf.Length ) zBuf.Length = n - 1; return zBuf.ToString(); }
/* ** Print into memory obtained from sqlite3Malloc(). Omit the internal ** %-conversion extensions. */ static string sqlite3_vmprintf( string zFormat, params va_list[] ap ) { string z; StringBuilder zBase = new StringBuilder( SQLITE_PRINT_BUF_SIZE ); StrAccum acc = new StrAccum(); #if !SQLITE_OMIT_AUTOINIT if ( sqlite3_initialize() != 0 ) return ""; #endif sqlite3StrAccumInit( acc, zBase, zBase.Length, SQLITE_PRINT_BUF_SIZE );//zBase).Length; sqlite3VXPrintf( acc, 0, zFormat, ap ); z = sqlite3StrAccumFinish( acc ); return z; }
/* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ static string sqlite3VMPrintf( sqlite3 db, string zFormat, params va_list[] ap ) { if ( zFormat == null ) return null; if ( ap.Length == 0 ) return zFormat; string z; StringBuilder zBase = new StringBuilder( SQLITE_PRINT_BUF_SIZE ); StrAccum acc = new StrAccum(); Debug.Assert( db != null ); sqlite3StrAccumInit( acc, zBase, zBase.Capacity, //zBase).Length; db.aLimit[SQLITE_LIMIT_LENGTH] ); acc.db = db; sqlite3VXPrintf( acc, 1, zFormat, ap ); z = sqlite3StrAccumFinish( acc ); // if ( acc.mallocFailed != 0 ) // { ////// db.mallocFailed = 1; // } return z; }
/* ** Reset an StrAccum string. Reclaim all malloced memory. */ static void sqlite3StrAccumReset( StrAccum p ) { //if ( p.zText.ToString() != p.zBase.ToString() ) //{ // if ( p.useMalloc == 1 ) // { // sqlite3DbFree( p.db, ref p.zText ); // } // else // { // sqlite3_free( ref p.zText ); // } //} p.zText.Length = 0; }
/* ** This function returns a pointer to a nul-terminated string in memory ** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the ** string contains a copy of zRawSql but with host parameters expanded to ** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1, ** then the returned string holds a copy of zRawSql with "-- " prepended ** to each line of text. ** ** The calling function is responsible for making sure the memory returned ** is eventually freed. ** ** ALGORITHM: Scan the input string looking for host parameters in any of ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within ** string literals, quoted identifier names, and comments. For text forms, ** the host parameter index is found by scanning the perpared ** statement for the corresponding OP_Variable opcode. Once the host ** parameter index is known, locate the value in p->aVar[]. Then render ** the value as a literal in place of the host parameter name. */ static string sqlite3VdbeExpandSql( Vdbe p, /* The prepared statement being evaluated */ string zRawSql /* Raw text of the SQL statement */ ) { sqlite3 db; /* The database connection */ int idx = 0; /* Index of a host parameter */ int nextIndex = 1; /* Index of next ? host parameter */ int n; /* Length of a token prefix */ int nToken = 0; /* Length of the parameter token */ int i; /* Loop counter */ Mem pVar; /* Value of a host parameter */ StrAccum _out = new StrAccum(1000); /* Accumulate the _output here */ StringBuilder zBase = new StringBuilder(100); /* Initial working space */ int izRawSql = 0; db = p.db; sqlite3StrAccumInit(_out, null, 100, db.aLimit[SQLITE_LIMIT_LENGTH]); _out.db = db; if (db.vdbeExecCnt > 1) { while (izRawSql < zRawSql.Length) { //string zStart = zRawSql; while (zRawSql[izRawSql++] != '\n' && izRawSql < zRawSql.Length) ; sqlite3StrAccumAppend(_out, "-- ", 3); sqlite3StrAccumAppend(_out, zRawSql, (int)izRawSql);//zRawSql - zStart ); } } else { while (izRawSql < zRawSql.Length) { n = findNextHostParameter(zRawSql, izRawSql, ref nToken); Debug.Assert(n > 0); sqlite3StrAccumAppend(_out, zRawSql.Substring(izRawSql, n), n); izRawSql += n; Debug.Assert(izRawSql < zRawSql.Length || nToken == 0); if (nToken == 0) break; if (zRawSql[izRawSql] == '?') { if (nToken > 1) { Debug.Assert(sqlite3Isdigit(zRawSql[izRawSql + 1])); sqlite3GetInt32(zRawSql, izRawSql + 1, ref idx); } else { idx = nextIndex; } } else { Debug.Assert(zRawSql[izRawSql] == ':' || zRawSql[izRawSql] == '$' || zRawSql[izRawSql] == '@'); testcase(zRawSql[izRawSql] == ':'); testcase(zRawSql[izRawSql] == '$'); testcase(zRawSql[izRawSql] == '@'); idx = sqlite3VdbeParameterIndex(p, zRawSql.Substring(izRawSql, nToken), nToken); Debug.Assert(idx > 0); } izRawSql += nToken; nextIndex = idx + 1; Debug.Assert(idx > 0 && idx <= p.nVar); pVar = p.aVar[idx - 1]; if ((pVar.flags & MEM_Null) != 0) { sqlite3StrAccumAppend(_out, "NULL", 4); } else if ((pVar.flags & MEM_Int) != 0) { sqlite3XPrintf(_out, "%lld", pVar.u.i); } else if ((pVar.flags & MEM_Real) != 0) { sqlite3XPrintf(_out, "%!.15g", pVar.r); } else if ((pVar.flags & MEM_Str) != 0) { #if !SQLITE_OMIT_UTF16 u8 enc = ENC(db); if( enc!=SQLITE_UTF8 ){ Mem utf8; memset(&utf8, 0, sizeof(utf8)); utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar.z, pVar.n, enc, SQLITE_STATIC); sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8); sqlite3XPrintf(_out, "'%.*q'", utf8.n, utf8.z); sqlite3VdbeMemRelease(&utf8); }else #endif { sqlite3XPrintf(_out, "'%.*q'", pVar.n, pVar.z); } } else if ((pVar.flags & MEM_Zero) != 0) { sqlite3XPrintf(_out, "zeroblob(%d)", pVar.u.nZero); } else { Debug.Assert((pVar.flags & MEM_Blob) != 0); sqlite3StrAccumAppend(_out, "x'", 2); for (i = 0; i < pVar.n; i++) { sqlite3XPrintf(_out, "%02x", pVar.zBLOB[i] & 0xff); } sqlite3StrAccumAppend(_out, "'", 1); } } } return sqlite3StrAccumFinish(_out); }
/* ** Initialize a string accumulator */ static void sqlite3StrAccumInit( StrAccum p, StringBuilder zBase, int n, int mx ) { //p.zBase.Length = 0; //if ( p.zBase.Capacity < n ) // p.zBase.Capacity = n; p.zText.Length = 0; if ( p.zText.Capacity < n ) p.zText.Capacity = n; p.db = null; //p.nChar = 0; //p.nAlloc = n; p.mxAlloc = mx; //p.useMalloc = 1; //p.tooBig = 0; //p.mallocFailed = 0; }
/* ** Finish off a string by making sure it is zero-terminated. ** Return a pointer to the resulting string. Return a NULL ** pointer if any kind of error was encountered. */ static string sqlite3StrAccumFinish( StrAccum p ) { //if (p.zText.Length > 0) //{ // p.zText[p.nChar] = 0; // if (p.useMalloc && p.zText == p.zBase) // { // p.zText = sqlite3DbMalloc(p.nChar + 1); // if (p.zText) // { // memcpy(p.zText, p.zBase, p.nChar + 1); // } // else // { // p.mallocFailed = 1; // } // } //} return p.zText.ToString(); }
/* ** Append N space characters to the given string buffer. */ static void appendSpace( StrAccum pAccum, int N ) { //static const char zSpaces[] = " "; //while( N>=zSpaces.Length-1 ){ // sqlite3StrAccumAppend(pAccum, zSpaces, zSpaces.Length-1); // N -= zSpaces.Length-1; //} //if( N>0 ){ // sqlite3StrAccumAppend(pAccum, zSpaces, N); //} pAccum.zText.AppendFormat( "{0," + N + "}", "" ); }
/* ** Reset an StrAccum string. Reclaim all malloced memory. */ static void sqlite3StrAccumReset( StrAccum p ) { if ( p.zText.ToString() != p.zBase.ToString() ) { sqlite3DbFree( p.db, ref p.zText ); } p.zText.Length = 0; }
/* ** This function returns a pointer to a nul-terminated string in memory ** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the ** string contains a copy of zRawSql but with host parameters expanded to ** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1, ** then the returned string holds a copy of zRawSql with "-- " prepended ** to each line of text. ** ** The calling function is responsible for making sure the memory returned ** is eventually freed. ** ** ALGORITHM: Scan the input string looking for host parameters in any of ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within ** string literals, quoted identifier names, and comments. For text forms, ** the host parameter index is found by scanning the perpared ** statement for the corresponding OP_Variable opcode. Once the host ** parameter index is known, locate the value in p->aVar[]. Then render ** the value as a literal in place of the host parameter name. */ static string sqlite3VdbeExpandSql( Vdbe p, /* The prepared statement being evaluated */ string zRawSql /* Raw text of the SQL statement */ ) { sqlite3 db; /* The database connection */ int idx = 0; /* Index of a host parameter */ int nextIndex = 1; /* Index of next ? host parameter */ int n; /* Length of a token prefix */ int nToken = 0; /* Length of the parameter token */ int i; /* Loop counter */ Mem pVar; /* Value of a host parameter */ StrAccum _out = new StrAccum(1000); /* Accumulate the _output here */ int izRawSql = 0; db = p.db; sqlite3StrAccumInit(_out, null, 100, db.aLimit[SQLITE_LIMIT_LENGTH]); _out.db = db; if (db.vdbeExecCnt > 1) { while (izRawSql < zRawSql.Length) { //string zStart = zRawSql; while (zRawSql[izRawSql++] != '\n' && izRawSql < zRawSql.Length) { ; } sqlite3StrAccumAppend(_out, "-- ", 3); sqlite3StrAccumAppend(_out, zRawSql, (int)izRawSql);//zRawSql - zStart ); } } else { while (izRawSql < zRawSql.Length) { n = findNextHostParameter(zRawSql, izRawSql, ref nToken); Debug.Assert(n > 0); sqlite3StrAccumAppend(_out, zRawSql.Substring(izRawSql, n), n); izRawSql += n; Debug.Assert(izRawSql < zRawSql.Length || nToken == 0); if (nToken == 0) { break; } if (zRawSql[izRawSql] == '?') { if (nToken > 1) { Debug.Assert(sqlite3Isdigit(zRawSql[izRawSql + 1])); sqlite3GetInt32(zRawSql, izRawSql + 1, ref idx); } else { idx = nextIndex; } } else { Debug.Assert(zRawSql[izRawSql] == ':' || zRawSql[izRawSql] == '$' || zRawSql[izRawSql] == '@'); testcase(zRawSql[izRawSql] == ':'); testcase(zRawSql[izRawSql] == '$'); testcase(zRawSql[izRawSql] == '@'); idx = sqlite3VdbeParameterIndex(p, zRawSql.Substring(izRawSql, nToken), nToken); Debug.Assert(idx > 0); } izRawSql += nToken; nextIndex = idx + 1; Debug.Assert(idx > 0 && idx <= p.nVar); pVar = p.aVar[idx - 1]; if ((pVar.flags & MEM_Null) != 0) { sqlite3StrAccumAppend(_out, "NULL", 4); } else if ((pVar.flags & MEM_Int) != 0) { sqlite3XPrintf(_out, "%lld", pVar.u.i); } else if ((pVar.flags & MEM_Real) != 0) { sqlite3XPrintf(_out, "%!.15g", pVar.r); } else if ((pVar.flags & MEM_Str) != 0) { #if !SQLITE_OMIT_UTF16 u8 enc = ENC(db); if (enc != SQLITE_UTF8) { Mem utf8; memset(&utf8, 0, sizeof(utf8)); utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar.z, pVar.n, enc, SQLITE_STATIC); sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8); sqlite3XPrintf(_out, "'%.*q'", utf8.n, utf8.z); sqlite3VdbeMemRelease(&utf8); } else #endif { sqlite3XPrintf(_out, "'%.*q'", pVar.n, pVar.z); } } else if ((pVar.flags & MEM_Zero) != 0) { sqlite3XPrintf(_out, "zeroblob(%d)", pVar.u.nZero); } else { Debug.Assert((pVar.flags & MEM_Blob) != 0); sqlite3StrAccumAppend(_out, "x'", 2); for (i = 0; i < pVar.n; i++) { sqlite3XPrintf(_out, "%02x", pVar.zBLOB[i] & 0xff); } sqlite3StrAccumAppend(_out, "'", 1); } } } return(sqlite3StrAccumFinish(_out)); }
/* ** Reset an StrAccum string. Reclaim all malloced memory. */ static void sqlite3StrAccumReset( StrAccum p ) { if ( p.zText.ToString() != p.zBase.ToString() ) { //sqlite3DbFree( p.db, ref p.zText ); } p.zText = new StringBuilder(); }