/* ** Usage: page_number PAGE ** ** Return the page number for a page. */ static int page_number( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ char zBuf[100]; DbPage *pPage; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PAGE\"", 0); return TCL_ERROR; } pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]); sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage)); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; }
/* ** Usage: btree_pager_stats ID ** ** Returns pager statistics */ static int btree_pager_stats( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int i; int *a; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); /* Normally in this file, with a b-tree handle opened using the ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly. ** But this function is sometimes called with a btree handle obtained ** from an open SQLite connection (using [btree_from_db]). In this case ** we need to obtain the mutex for the controlling SQLite handle before ** it is safe to call sqlite3BtreeEnter(). */ sqlite3_mutex_enter(pBt->db->mutex); sqlite3BtreeEnter(pBt); a = sqlite3PagerStats(sqlite3BtreePager(pBt)); for(i=0; i<11; i++){ static char *zName[] = { "ref", "page", "max", "size", "state", "err", "hit", "miss", "ovfl", "read", "write" }; char zBuf[100]; Tcl_AppendElement(interp, zName[i]); sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); Tcl_AppendElement(interp, zBuf); } sqlite3BtreeLeave(pBt); /* Release the mutex on the SQLite handle that controls this b-tree */ sqlite3_mutex_leave(pBt->db->mutex); return TCL_OK; }
/* ** Argument zPath points to a nul-terminated string containing a file path. ** If zPath is an absolute path, then it is copied as is into the output ** buffer. Otherwise, if it is a relative path, then the equivalent full ** path is written to the output buffer. ** ** This function assumes that paths are UNIX style. Specifically, that: ** ** 1. Path components are separated by a '/'. and ** 2. Full paths begin with a '/' character. */ static int demoFullPathname( sqlite3_vfs *pVfs, /* VFS */ const char *zPath, /* Input path (possibly a relative path) */ int nPathOut, /* Size of output buffer in bytes */ char *zPathOut /* Pointer to output buffer */ ){ char zDir[MAXPATHNAME+1]; if( zPath[0]=='/' ){ zDir[0] = '\0'; }else{ getcwd(zDir, sizeof(zDir)); } zDir[MAXPATHNAME] = '\0'; sqlite3_snprintf(nPathOut, zPathOut, "%s/%s", zDir, zPath); zPathOut[nPathOut-1] = '\0'; return SQLITE_OK; }
/* ** Usage: btree_cursor ID TABLENUM WRITEABLE ** ** Create a new cursor. Return the ID for the cursor. */ static int btree_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int iTable; BtCursor *pCur; int rc = SQLITE_OK; int wrFlag; char zBuf[30]; if( argc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID TABLENUM WRITEABLE\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; if( wrFlag ) wrFlag = BTREE_WRCSR; pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); memset(pCur, 0, sqlite3BtreeCursorSize()); sqlite3_mutex_enter(pBt->db->mutex); sqlite3BtreeEnter(pBt); #ifndef SQLITE_OMIT_SHARED_CACHE rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag); #endif if( rc==SQLITE_OK ){ rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); } sqlite3BtreeLeave(pBt); sqlite3_mutex_leave(pBt->db->mutex); if( rc ){ ckfree((char *)pCur); Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; }
/* ** Print an error message */ static void errorMessage(const char *zFormat, ...){ va_list ap; char *zMsg; char zPrefix[30]; va_start(ap, zFormat); zMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:ERROR: ", g.zName); if( g.pLog ){ printWithPrefix(g.pLog, zPrefix, zMsg); fflush(g.pLog); } if( g.pErrLog && safe_strcmp(g.zErrLog,g.zLog) ){ printWithPrefix(g.pErrLog, zPrefix, zMsg); fflush(g.pErrLog); } sqlite3_free(zMsg); g.nError++; }
static int set_repo_user_version(sqlite3 *sqlite, const char *database, int reposcver) { int retcode = EPKG_OK; char sql[BUFSIZ]; char *errmsg; const char *fmt = "PRAGMA %Q.user_version = %d;" ; assert(database != NULL); sqlite3_snprintf(sizeof(sql), sql, fmt, database, reposcver); if (sqlite3_exec(sqlite, sql, NULL, NULL, &errmsg) != SQLITE_OK) { pkg_emit_error("sqlite: %s", errmsg); sqlite3_free(errmsg); retcode = EPKG_FATAL; } return (retcode); }
static int btreeSeqOpen( sqlite3_context *context, Btree *p, SEQ_COOKIE *cookie) { BtShared *pBt; DBT key; DB_SEQUENCE *seq; char seq_key[BT_MAX_SEQ_NAME]; int ret, seq_len; u_int32_t flags; pBt = p->pBt; if ((ret = btreeSeqGetCookie(context, p, cookie, 0)) != 0) return (ret); if (cookie->cache != 0) { if ((ret = db_sequence_create(&seq, pBt->metadb, 0)) != 0) return ret; seq->set_cachesize(seq, cookie->cache); flags = 0; #ifdef BDBSQL_SINGLE_THREAD flags |= DB_THREAD; #endif sqlite3_snprintf( BT_MAX_SEQ_NAME, seq_key, "%s_db", cookie->name); seq_len = (int)strlen(seq_key); memset(&key, 0, sizeof(key)); key.data = seq_key; key.size = key.ulen = seq_len; key.flags = DB_DBT_USERMEM; if ((ret = seq->open( seq, NULL, &key, flags)) != 0) { (void)seq->close(seq, 0); return ret; } cookie->handle = seq; } return (0); }
/* ** Guess the mime-type of a document based on its name. */ const char *mimetype_from_name(const char *zName){ const char *z; int i; int first, last; int len; char zSuffix[20]; #ifdef FOSSIL_DEBUG /* This is test code to make sure the table above is in the correct ** order */ if( fossil_strcmp(zName, "mimetype-test")==0 ){ mimetype_verify(); return "ok"; } #endif z = zName; for(i=0; zName[i]; i++){ if( zName[i]=='.' ) z = &zName[i+1]; } len = strlen(z); if( len<sizeof(zSuffix)-1 ){ sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z); for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]); first = 0; last = ArraySize(aMime) - 1; while( first<=last ){ int c; i = (first+last)/2; c = fossil_strcmp(zSuffix, aMime[i].zSuffix); if( c==0 ) return aMime[i].zMimetype; if( c<0 ){ last = i-1; }else{ first = i+1; } } } return "application/x-fossil-artifact"; }
static int btreeCleanupEnv(const char *home) { DB_ENV *tmp_env; int count, i, ret; char **names, buf[512]; log_msg(LOG_DEBUG, "btreeCleanupEnv removing existing env."); /* * If there is a directory (environment), but no * database file. Clear the environment to avoid * carrying over information from earlier sessions. */ if ((ret = db_env_create(&tmp_env, 0)) != 0) return ret; /* Remove log files */ if ((ret = __os_dirlist(tmp_env->env, home, 0, &names, &count)) != 0) { (void)tmp_env->close(tmp_env, 0); return ret; } for (i = 0; i < count; i++) { if (strncmp(names[i], "log.", 4) != 0) continue; sqlite3_snprintf(sizeof(buf), buf, "%s%s%s", home, "/", names[i]); /* * Use Berkeley DB __os_unlink (not sqlite3OsDelete) since * this file has always been managed by Berkeley DB. */ (void)__os_unlink(NULL, buf, 0); } __os_dirfree(tmp_env->env, names, count); /* * TODO: Do we want force here? Ideally all handles * would always be closed on exit, so DB_FORCE would * not be necessary. The world is not currently ideal. */ return tmp_env->remove(tmp_env, home, DB_FORCE); }
/* ** Shared-memory operations. */ static int vfstraceShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ vfstrace_file *p = (vfstrace_file *)pFile; vfstrace_info *pInfo = p->pInfo; int rc; char zLck[100]; int i = 0; memcpy(zLck, "|0", 3); if( flags & SQLITE_SHM_UNLOCK ) strappend(zLck, &i, "|UNLOCK"); if( flags & SQLITE_SHM_LOCK ) strappend(zLck, &i, "|LOCK"); if( flags & SQLITE_SHM_SHARED ) strappend(zLck, &i, "|SHARED"); if( flags & SQLITE_SHM_EXCLUSIVE ) strappend(zLck, &i, "|EXCLUSIVE"); if( flags & ~(0xf) ){ sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags); } vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d,n=%d,%s)", pInfo->zVfsName, p->zFName, ofst, n, &zLck[1]); rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); vfstrace_print_errcode(pInfo, " -> %s\n", rc); return rc; }
/* ** Sync an vfstrace-file. */ static int vfstraceSync(sqlite3_file *pFile, int flags){ vfstrace_file *p = (vfstrace_file *)pFile; vfstrace_info *pInfo = p->pInfo; int rc; int i; char zBuf[100]; memcpy(zBuf, "|0", 3); i = 0; if( flags & SQLITE_SYNC_FULL ) strappend(zBuf, &i, "|FULL"); else if( flags & SQLITE_SYNC_NORMAL ) strappend(zBuf, &i, "|NORMAL"); if( flags & SQLITE_SYNC_DATAONLY ) strappend(zBuf, &i, "|DATAONLY"); if( flags & ~(SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY) ){ sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags); } vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo->zVfsName, p->zFName, &zBuf[1]); rc = p->pReal->pMethods->xSync(p->pReal, flags); vfstrace_printf(pInfo, " -> %d\n", rc); return rc; }
static int pager_pagecount( void *NotUsed, Tcl_Interp *interp, int argc, const char **argv ){ Pager *pPager; char zBuf[100]; int nPage; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); sqlite3PagerPagecount(pPager, &nPage); sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nPage); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; }
/* ** Usage: pager_pagecount ID ** ** Return the size of the database file. */ static int SQLITE_TCLAPI pager_pagecount( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; int nPage; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); sqlite3PagerPagecount(pPager, &nPage); sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nPage); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; }
/* ** COMMAND: rstats ** ** Usage: %fossil rstats ** ** Deliver a report of the repository statistics for the ** current checkout. */ void rstats_cmd(void){ i64 t; int n, m, fsize, vid; char zBuf[100]; db_must_be_within_tree(); vid = db_lget_int("checkout",0); if( vid==0 ){ fossil_panic("no checkout"); } fsize = file_size(g.zRepositoryName); n = db_int(0, "SELECT count(*) FROM blob"); m = db_int(0, "SELECT count(*) FROM delta"); printf(" Number of Artifacts: %d\n", n); printf(" %d full text + %d delta blobs\n", (n-m), m); if( n>0 ){ int a, b; t = db_int64(0, "SELECT total(size) FROM blob WHERE size>0"); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", t); if( t/fsize < 5 ){ b = 10; fsize /= 10; }else{ b = 1; } a = t/fsize; printf(" %d bytes average, %s bytes total\n\n", ((int)(((double)t)/(double)n)), (zBuf)); } n = db_int(0, "SELECT count(distinct mid) FROM mlink"); printf(" Number Of Checkins: %d\n", n); n = db_int(0, "SELECT count(*) FROM filename"); printf(" Number Of Files: %d\n", n); n = db_int(0, "SELECT count(*) FROM tag WHERE +tagname GLOB 'wiki-*'"); printf("Number Of Wiki Pages: %d\n", n); n = db_int(0, "SELECT count(*) FROM tag WHERE +tagname GLOB 'tkt-*'"); printf(" Number Of Tickets: %d\n", n); n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event) + 0.99"); printf(" Duration Of Project: %d days\n", n); }
/* ** Usage: btree_open FILENAME NCACHE ** ** Open a new database */ static int btree_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc, nCache; char zBuf[100]; int n; char *zFilename; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME NCACHE FLAGS\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; nRefSqlite3++; if( nRefSqlite3==1 ){ sDb.pVfs = sqlite3_vfs_find(0); sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); sqlite3_mutex_enter(sDb.mutex); } n = (int)strlen(argv[1]); zFilename = sqlite3_malloc( n+2 ); if( zFilename==0 ) return TCL_ERROR; memcpy(zFilename, argv[1], n+1); zFilename[n+1] = 0; rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); sqlite3_free(zFilename); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3BtreeSetCacheSize(pBt, nCache); sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; }
/* ** Compute an aggregate MD5 checksum over the repository image of every ** file in manifest vid. The file names are part of the checksum. The ** resulting checksum is suitable for use as the R-card of a manifest. ** ** Return the resulting checksum in blob pOut. ** ** If pManOut is not NULL then fill it with the checksum found in the ** "R" card near the end of the manifest. ** ** In a well-formed manifest, the two checksums computed here, pOut and ** pManOut, should be identical. */ void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){ int fid; Blob file; Blob err; Manifest *pManifest; ManifestFile *pFile; char zBuf[100]; blob_zero(pOut); blob_zero(&err); if( pManOut ){ blob_zero(pManOut); } db_must_be_within_tree(); pManifest = manifest_get(vid, CFTYPE_MANIFEST, &err); if( pManifest==0 ){ fossil_fatal("manifest file (%d) is malformed:\n%s\n", vid, blob_str(&err)); } manifest_file_rewind(pManifest); while( (pFile = manifest_file_next(pManifest,0))!=0 ){ if( pFile->zUuid==0 ) continue; fid = uuid_to_rid(pFile->zUuid, 0); md5sum_step_text(pFile->zName, -1); content_get(fid, &file); sqlite3_snprintf(sizeof(zBuf), zBuf, " %d\n", blob_size(&file)); md5sum_step_text(zBuf, -1); md5sum_step_blob(&file); blob_reset(&file); } if( pManOut ){ if( pManifest->zRepoCksum ){ blob_append(pManOut, pManifest->zRepoCksum, -1); }else{ blob_zero(pManOut); } } manifest_destroy(pManifest); md5sum_finish(pOut); }
std::string DatabaseSQLite::escapeString(const std::string &s) { // remember about quoiting even an empty string! if(!s.size()) return std::string("''"); // the worst case is 2n + 3 char* output = new char[s.length() * 2 + 3]; // quotes escaped string and frees temporary buffer sqlite3_snprintf(s.length() * 2 + 1, output, "%Q", s.c_str()); std::string r(output); delete[] output; //escape % and _ because we are using LIKE operator. r = boost::regex_replace(r, boost::regex("%"), "\\%"); r = boost::regex_replace(r, boost::regex("_"), "\\_"); if(r[r.length() - 1] != '\'') r += "'"; return r; }
/* ** Usage: btree_move_to ID KEY ** ** Move the cursor to the entry with the given key. */ static int btree_move_to( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; int res; char zBuf[20]; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID KEY\"", 0); return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ int iKey; if( Tcl_GetInt(interp, argv[2], &iKey) ){ sqlite3BtreeLeave(pCur->pBtree); return TCL_ERROR; } rc = sqlite3BtreeMovetoUnpacked(pCur, 0, iKey, 0, &res); }else{ rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res); } sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } if( res<0 ) res = -1; if( res>0 ) res = 1; sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; }
/* ** Run arbitrary SQL and record the results in an output string ** given by the first parameter. */ static int evalSql(String *p, const char *zFormat, ...){ va_list ap; char *zSql; int rc; char *zErrMsg = 0; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); assert( g.iTimeout>0 ); rc = sqlite3_exec(g.db, zSql, evalCallback, p, &zErrMsg); sqlite3_free(zSql); if( rc ){ char zErr[30]; sqlite3_snprintf(sizeof(zErr), zErr, "error(%d)", rc); stringAppendTerm(p, zErr); if( zErrMsg ){ stringAppendTerm(p, zErrMsg); sqlite3_free(zErrMsg); } } return rc; }
int seafile_session_config_set_string (SeafileSession *session, const char *key, const char *value) { char sql[256]; sqlite3_snprintf (sizeof(sql), sql, "REPLACE INTO Config VALUES ('%q', '%q');", key, value); if (sqlite_query_exec (session->config_db, sql) < 0) return -1; if (g_strcmp0(key, KEY_SYNC_EXTRA_TEMP_FILE) == 0) { if (g_strcmp0(value, "true") == 0) session->sync_extra_temp_file = TRUE; else session->sync_extra_temp_file = FALSE; } return 0; }
/* ** Usage: btree_eof ID ** ** Return TRUE if the given cursor is not pointing at a valid entry. ** Return FALSE if the cursor does point to a valid entry. */ static int btree_eof( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; char zBuf[50]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeEof(pCur); sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; }
/* ** Add a single file to the growing tarball. */ static void tar_add_file( const char *zName, /* Name of the file. nul-terminated */ Blob *pContent, /* Content of the file */ int mPerm, /* 1: executable file, 2: symlink */ unsigned int mTime /* Last modification time of the file */ ){ int nName = strlen(zName); int n = blob_size(pContent); int lastPage; char cType = '0'; /* length check moved to tar_split_path */ tar_add_directory_of(zName, nName, mTime); /* * If we have a symlink, write its destination path (which is stored in * pContent) into header, and set content length to 0 to avoid storing path * as file content in the next step. Since 'linkname' header is limited to * 100 bytes (-1 byte for terminating zero), if path is greater than that, * store symlink as a plain-text file. (Not sure how TAR handles long links.) */ if( mPerm == PERM_LNK && n <= 100 ){ sqlite3_snprintf(100, (char*)&tball.aHdr[157], "%s", blob_str(pContent)); cType = '2'; n = 0; } tar_add_header(zName, nName, ( mPerm==PERM_EXE ) ? 0755 : 0644, mTime, n, cType); if( n ){ gzip_step(blob_buffer(pContent), n); lastPage = n % 512; if( lastPage!=0 ){ gzip_step(tball.zSpaces, 512 - lastPage); } } }
static int page_lookup( void *NotUsed, Tcl_Interp *interp, int argc, const char **argv ){ Pager *pPager; char zBuf[100]; DbPage *pPage; int pgno; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID PGNO\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; pPage = sqlite3PagerLookup(pPager, pgno); if( pPage ){ sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); Tcl_AppendResult(interp, zBuf, 0); } return TCL_OK; }
/* ** Usage: page_lookup ID PGNO ** ** Return a pointer to a page if the page is already in cache. ** If not in cache, return an empty string. */ static int page_lookup( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; DbPage *pPage; int pgno; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID PGNO\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; pPage = sqlite3PagerLookup(pPager, pgno); if( pPage ){ sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); Tcl_AppendResult(interp, zBuf, 0); } return TCL_OK; }
/* ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) ** ** Return a string described by FORMAT. Conversions as follows: ** ** %d day of month ** %f ** fractional seconds SS.SSS ** %H hour 00-24 ** %j day of year 000-366 ** %J ** julian day number ** %m month 01-12 ** %M minute 00-59 ** %s seconds since 1970-01-01 ** %S seconds 00-59 ** %w day of week 0-6 sunday==0 ** %W week of year 00-53 ** %Y year 0000-9999 ** %% % */ static void strftimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; u64 n; size_t i,j; char *z; sqlite3 *db; const char *zFmt; char zBuf[100]; if( argc==0 ) return; zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); for(i=0, n=1; zFmt[i]; i++, n++){ if( zFmt[i]=='%' ){ switch( zFmt[i+1] ){ case 'd': case 'H': case 'm': case 'M': case 'S': case 'W': n++; /* fall thru */ case 'w': case '%': break; case 'f': n += 8; break; case 'j': n += 3; break; case 'Y': n += 8; break; case 's': case 'J': n += 50; break; default: return; /* ERROR. return a NULL */ } i++; } } testcase( n==sizeof(zBuf)-1 ); testcase( n==sizeof(zBuf) ); testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ); if( n<sizeof(zBuf) ){ z = zBuf; }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); return; }else{ z = sqlite3DbMallocRawNN(db, (int)n); if( z==0 ){ sqlite3_result_error_nomem(context); return; } } computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ if( zFmt[i]!='%' ){ z[j++] = zFmt[i]; }else{ i++; switch( zFmt[i] ){ case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; case 'f': { double s = x.s; if( s>59.999 ) s = 59.999; sqlite3_snprintf(7, &z[j],"%06.3f", s); j += sqlite3Strlen30(&z[j]); break; } case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; case 'W': /* Fall thru */ case 'j': { int nDay; /* Number of days since 1st day of year */ DateTime y = x; y.validJD = 0; y.M = 1; y.D = 1; computeJD(&y); nDay = (int)((x.iJD-y.iJD+43200000)/86400000); if( zFmt[i]=='W' ){ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ wd = (int)(((x.iJD+43200000)/86400000)%7); sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); j += 2; }else{ sqlite3_snprintf(4, &z[j],"%03d",nDay+1); j += 3; } break; } case 'J': { sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); j+=sqlite3Strlen30(&z[j]); break; } case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; case 's': { sqlite3_snprintf(30,&z[j],"%lld", (i64)(x.iJD/1000 - 21086676*(i64)10000)); j += sqlite3Strlen30(&z[j]); break; } case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; case 'w': { z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; break; } case 'Y': { sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); break; } default: z[j++] = '%'; break; } } } z[j] = 0; sqlite3_result_text(context, z, -1, z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC); }
static void db_seq_create_func( sqlite3_context *context, int argc, sqlite3_value **argv) { Btree *p; BtShared *pBt; SEQ_COOKIE cookie; int i, rc; sqlite3 *db; if (argc < 1) { btreeSeqError(context, SQLITE_ERROR, "wrong number of arguments to function " "create_sequence()"); return; } /* * Ensure that the sequence name is OK with our static buffer * size. We need extra characters for "seq_" and "_db". */ if (strlen((const char *)sqlite3_value_text(argv[0])) > BT_MAX_SEQ_NAME - 8) { btreeSeqError(context, SQLITE_ERROR, "Sequence name too long."); return; } db = sqlite3_context_db_handle(context); /* * TODO: How do we know which BtShared to use? * What if there are multiple attached DBs, can the user specify which * one to create the sequence on? */ p = db->aDb[0].pBt; pBt = p->pBt; if (!p->connected && (rc = btreeOpenEnvironment(p, 1)) != SQLITE_OK) { btreeSeqError(context, SQLITE_ERROR, "%sconnection could not be opened.", MSG_CREATE_FAIL); return; } /* The cookie holds configuration information. */ memset(&cookie, 0, sizeof(SEQ_COOKIE)); cookie.incr = 1; sqlite3_snprintf(BT_MAX_SEQ_NAME, cookie.name, "seq_%s", sqlite3_value_text(argv[0])); cookie.name_len = (int)strlen(cookie.name); if (pBt->dbStorage == DB_STORE_NAMED && btreeSeqExists(context, p, cookie.name) == 1) { btreeSeqError(context, SQLITE_ERROR, "Attempt to call sequence_create when a sequence " "already exists."); return; } /* * TODO: In the future calling create_sequence when there is already a * handle in the cache could be used to alter the "cookie" values. * Don't do that for now, because it requires opening and closing * the DB handle, which needs care if it's being used by * multiple threads. */ /* Set the boundary values to distinguish if user set the values. */ cookie.min_val = -INT64_MAX; cookie.max_val = INT64_MAX; cookie.start_val = -INT64_MAX; /* Parse options. */ for (i = 1; i < argc; i++) { if (strncmp((char *)sqlite3_value_text(argv[i]), "cache", 5) == 0) { if (i == argc || sqlite3_value_type(argv[++i]) != SQLITE_INTEGER) { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } cookie.cache = sqlite3_value_int(argv[i]); } else if (strncmp((char *)sqlite3_value_text(argv[i]), "incr", 4) == 0) { if (i == argc || sqlite3_value_type(argv[++i]) != SQLITE_INTEGER) { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } cookie.incr = sqlite3_value_int(argv[i]); } else if (strncmp((char *)sqlite3_value_text(argv[i]), "maxvalue", 8) == 0) { if (i == argc || sqlite3_value_type(argv[++i]) != SQLITE_INTEGER) { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } cookie.max_val = sqlite3_value_int(argv[i]); } else if (strncmp((char *)sqlite3_value_text(argv[i]), "minvalue", 8) == 0) { if (i == argc || sqlite3_value_type(argv[++i]) != SQLITE_INTEGER) { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } cookie.min_val = sqlite3_value_int(argv[i]); } else if (strncmp((char *)sqlite3_value_text(argv[i]), "start", 5) == 0) { if (i == argc || sqlite3_value_type(argv[++i]) != SQLITE_INTEGER) { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } cookie.start_val = sqlite3_value_int(argv[i]); } else { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } } /* * Setup the cookie. Do this after the parsing so param order doesn't * matter. */ if (cookie.incr < 0) { cookie.decrementing = 1; cookie.incr = -cookie.incr; } /* Attempt to give a reasonable default start value. */ if (cookie.start_val == -INT64_MAX) { /* * Set a reasonable default start value, if * only half of a range has been given. */ if (cookie.decrementing == 1 && cookie.max_val != INT64_MAX) { cookie.start_val = cookie.max_val; } else if (cookie.decrementing == 0 && cookie.min_val != -INT64_MAX) { cookie.start_val = cookie.min_val; } else { /* * If user does not set start_val, min_val and * max_val, set default start_val to 0 by default. */ cookie.start_val = 0; } } /* Validate the settings. */ if (cookie.min_val > cookie.max_val && cookie.max_val != 0) { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } if (cookie.min_val > cookie.start_val || cookie.max_val < cookie.start_val) { btreeSeqError(context, SQLITE_ERROR, "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } if (cookie.cache != 0 && db->autoCommit == 0) { btreeSeqError(context, SQLITE_ERROR, "Cannot create caching sequence in a transaction."); goto err; } if ((rc = btreeSeqGetHandle(context, p, SEQ_HANDLE_CREATE, &cookie)) != SQLITE_OK) { if (rc != SQLITE_ERROR) btreeSeqError(context, dberr2sqlite(rc, NULL), "Failed to create sequence %s. Error: %s", (const char *)sqlite3_value_text(argv[0]), db_strerror(rc)); goto err; } sqlite3_result_int(context, SQLITE_OK); err: return; }
static int btreeSeqGetHandle(sqlite3_context *context, Btree *p, int mode, SEQ_COOKIE *cookie) { BtShared *pBt; CACHED_DB *cache_entry, *stale_db; int ret; cache_entry = NULL; ret = SQLITE_OK; pBt = p->pBt; /* Does not support in-memory db and temp db for now */ if (pBt->dbStorage != DB_STORE_NAMED) { btreeSeqError(context, SQLITE_ERROR, "Sequences do not support in-memory or " "temporary databases."); return (SQLITE_ERROR); } /* * The process here is: * - Is the handle already in the cache - if so, just return. * - Else, does the sequence already exist: * + No: create the sequence * - open a handle and add it to the cache * * Use the cookie to store the name. If the handle is cached, the value * will be overwritten. */ sqlite3_mutex_enter(pBt->mutex); cache_entry = sqlite3HashFind(&pBt->db_cache, cookie->name, cookie->name_len); sqlite3_mutex_leave(pBt->mutex); if (CACHE_ENTRY_VALID(cache_entry)) { /* Check to see if the handle is no longer valid. */ if (btreeSeqExists(context, p, cookie->name) == 0) { btreeSeqRemoveHandle(context, p, cache_entry); return (DB_NOTFOUND); } if (mode == SEQ_HANDLE_OPEN) { assert(cache_entry->cookie != NULL); memcpy(cookie, cache_entry->cookie, sizeof(SEQ_COOKIE)); cookie->handle = (DB_SEQUENCE *)cache_entry->dbp; return (SQLITE_OK); } else if (mode == SEQ_HANDLE_CREATE) { cookie->handle = NULL; return (DB_KEYEXIST); } } /* * The handle wasn't found; Get seq handle by open or create the * sequence with the given name. */ if ((ret = btreeSeqOpen(context, p, cookie)) != 0) { if (mode == SEQ_HANDLE_CREATE) ret = btreeSeqCreate(context, p, cookie); } else if (mode == SEQ_HANDLE_CREATE) { return DB_KEYEXIST; } if (ret != 0) { if (cookie->handle != NULL) cookie->handle->close(cookie->handle, 0); return (ret); } /* * We dropped the pBt->mutex after the lookup failed, grab it * again before inserting into the cache. That means there is a race * adding the handle to the cache, so we need to deal with that. */ sqlite3_mutex_enter(pBt->mutex); /* Check to see if someone beat us to adding the handle. */ cache_entry = sqlite3HashFind(&pBt->db_cache, cookie->name, cookie->name_len); if (CACHE_ENTRY_VALID(cache_entry)) { cookie->handle->close(cookie->handle, 0); cookie->handle = (DB_SEQUENCE *)cache_entry->dbp; goto err; } /* Add the new handle to the cache. */ if ((cache_entry = (CACHED_DB *)sqlite3_malloc(sizeof(CACHED_DB))) == NULL) { btreeSeqError(context, SQLITE_NOMEM, "Memory allocation failure during sequence create."); ret = SQLITE_NOMEM; goto err; } memset(cache_entry, 0, sizeof(CACHED_DB)); if ((cache_entry->cookie = (SEQ_COOKIE *)sqlite3_malloc(sizeof(SEQ_COOKIE))) == NULL) { btreeSeqError(context, SQLITE_NOMEM, "Memory allocation failure during sequence create."); ret = SQLITE_NOMEM; goto err; } sqlite3_snprintf( sizeof(cache_entry->key), cache_entry->key, cookie->name); /* * Hack alert! * We're assigning the sequence to the DB pointer in the cached entry * it makes everything simpler, since much of the code in btree.c is * coded assuming dbp will be populated. It just means we need to be a * bit careful using DB handles from the cache now. */ cache_entry->dbp = (DB *)cookie->handle; cache_entry->is_sequence = 1; memcpy(cache_entry->cookie, cookie, sizeof(SEQ_COOKIE)); stale_db = sqlite3HashInsert(&pBt->db_cache, cache_entry->key, cookie->name_len, cache_entry); if (stale_db) { sqlite3_free(stale_db); /* * Hash table out of memory when returned pointer is * same as the original value pointer. */ if (stale_db == cache_entry) { btreeSeqError(context, SQLITE_NOMEM, MSG_MALLOC_FAIL); ret = SQLITE_NOMEM; goto err; } } err: sqlite3_mutex_leave(pBt->mutex); if (ret != 0 && cache_entry != NULL) { if (cache_entry->cookie != NULL) sqlite3_free(cache_entry->cookie); sqlite3_free(cache_entry); } return (ret); }
static void btreeSeqGetVal( sqlite3_context *context, const char * name, int mode) { Btree *p; BtShared *pBt; SEQ_COOKIE cookie; db_seq_t val; int rc, ret; sqlite3 *db; db = sqlite3_context_db_handle(context); p = db->aDb[0].pBt; pBt = p->pBt; memset(&cookie, 0, sizeof(cookie)); if (!p->connected && (rc = btreeOpenEnvironment(p, 1)) != SQLITE_OK) { sqlite3_result_error(context, "Sequence open failed: connection could not be opened.", -1); return; } sqlite3_snprintf(BT_MAX_SEQ_NAME, cookie.name, "seq_%s", name); cookie.name_len = (int)strlen(cookie.name); rc = btreeSeqGetHandle(context, p, SEQ_HANDLE_OPEN, &cookie); if (rc != SQLITE_OK) { if (rc == DB_NOTFOUND) btreeSeqError(context, dberr2sqlite(rc, NULL), "no such sequence: %s", name); else if (rc != SQLITE_ERROR) btreeSeqError(context, dberr2sqlite(rc, NULL), "Fail to get next value from seq %s. Error: %s", name, db_strerror(rc)); return; } if (cookie.cache == 0) { /* * Ensure we see the latest value across connections. Use * DB_RMW to ensure that no other process changes the value * while we're updating it. */ if ((ret = btreeSeqGetCookie(context, p, &cookie, DB_RMW)) != 0) { btreeSeqError(context, SQLITE_ERROR, "Failed to retrieve sequence value. Error: %s", db_strerror(ret)); return; } if (mode == DB_SEQ_NEXT) { /* Bounds check. */ if (cookie.used && ((cookie.decrementing && cookie.val - cookie.incr < cookie.min_val) || (!cookie.decrementing && cookie.val + cookie.incr > cookie.max_val))) { btreeSeqError(context, SQLITE_ERROR, "Sequence value out of bounds."); return; } if (!cookie.used) { cookie.used = 1; cookie.val = cookie.start_val; } else if (cookie.decrementing) cookie.val -= cookie.incr; else cookie.val += cookie.incr; btreeSeqPutCookie(context, p, &cookie, 0); } else if (!cookie.used) { btreeSeqError(context, SQLITE_ERROR, "Can't call currval on an unused sequence."); return ; } val = cookie.val; } else { if (mode == DB_SEQ_CURRENT) { btreeSeqError(context, SQLITE_ERROR, "Can't call currval on a caching sequence."); return; } /* * Using a cached sequence while an exclusive transaction is * active on this handle causes a hang. Avoid it. */ if (p->txn_excl == 1) { btreeSeqError(context, SQLITE_ERROR, "Can't call nextval on a caching sequence while an" " exclusive transaction is active."); return; } /* Cached gets can't be transactionally protected. */ if ((ret = cookie.handle->get(cookie.handle, NULL, cookie.incr, &val, 0)) != 0) { if (ret == EINVAL) btreeSeqError(context, SQLITE_ERROR, "Sequence value out of bounds."); else btreeSeqError(context, SQLITE_ERROR, "Failed sequence get. Error: %s", db_strerror(ret)); return; } } sqlite3_result_int64(context, val); }
static void db_seq_drop_func( sqlite3_context *context, int argc, sqlite3_value **argv) { Btree *p; BtShared *pBt; CACHED_DB *cache_entry; SEQ_COOKIE cookie; int mutex_held, rc; sqlite3 *db; db = sqlite3_context_db_handle(context); p = db->aDb[0].pBt; pBt = p->pBt; mutex_held = 0; memset(&cookie, 0, sizeof(cookie)); if (!p->connected && (rc = btreeOpenEnvironment(p, 1)) != SQLITE_OK) { btreeSeqError(context, SQLITE_ERROR, "Sequence drop failed: connection could not be opened."); return; } sqlite3_snprintf(BT_MAX_SEQ_NAME, cookie.name, "seq_%s", sqlite3_value_text(argv[0])); cookie.name_len = (int)strlen(cookie.name); rc = btreeSeqGetHandle(context, p, SEQ_HANDLE_OPEN, &cookie); if (rc != SQLITE_OK) { /* If the handle doesn't exist, return an error. */ if (rc == DB_NOTFOUND) btreeSeqError(context, dberr2sqlite(rc, NULL), "no such sequence: %s", cookie.name + 4); else if (rc != SQLITE_ERROR) btreeSeqError(context, dberr2sqlite(rc, NULL), "Fail to drop sequence %s. Error: %s", cookie.name + 4, db_strerror(rc)); return; } sqlite3_mutex_enter(pBt->mutex); mutex_held = 1; cache_entry = sqlite3HashFind(&pBt->db_cache, cookie.name, cookie.name_len); if (cache_entry == NULL) goto done; if (cookie.cache != 0 && db->autoCommit == 0) { btreeSeqError(context, SQLITE_ERROR, "Cannot drop caching sequence in a transaction."); rc = SQLITE_ERROR; goto done; } sqlite3_mutex_leave(pBt->mutex); if ((rc = btreeSeqStartTransaction(context, p, 1)) != SQLITE_OK) { btreeSeqError(context, SQLITE_ERROR, "Could not begin transaction for drop."); return; } /* * Drop the mutex - it's not valid to begin a transaction while * holding the mutex. We can drop it safely because it's use is to * protect handle cache changes. */ sqlite3_mutex_enter(pBt->mutex); btreeSeqRemoveHandle(context, p, cache_entry); done: sqlite3_mutex_leave(pBt->mutex); if (rc == SQLITE_OK) sqlite3_result_int(context, SQLITE_OK); }
int seaf_branch_manager_add_branch (SeafBranchManager *mgr, SeafBranch *branch) { #ifndef SEAFILE_SERVER char sql[256]; pthread_mutex_lock (&mgr->priv->db_lock); sqlite3_snprintf (sizeof(sql), sql, "SELECT 1 FROM Branch WHERE name=%Q and repo_id=%Q", branch->name, branch->repo_id); if (sqlite_check_for_existence (mgr->priv->db, sql)) sqlite3_snprintf (sizeof(sql), sql, "UPDATE Branch SET commit_id=%Q WHERE " "name=%Q and repo_id=%Q", branch->commit_id, branch->name, branch->repo_id); else sqlite3_snprintf (sizeof(sql), sql, "INSERT INTO Branch VALUES (%Q, %Q, %Q)", branch->name, branch->repo_id, branch->commit_id); sqlite_query_exec (mgr->priv->db, sql); pthread_mutex_unlock (&mgr->priv->db_lock); return 0; #else char *sql; SeafDB *db = mgr->seaf->db; if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { gboolean exists, err; int rc; sql = "SELECT repo_id FROM Branch WHERE name=? AND repo_id=?"; exists = seaf_db_statement_exists(db, sql, &err, 2, "string", branch->name, "string", branch->repo_id); if (err) return -1; if (exists) rc = seaf_db_statement_query (db, "UPDATE Branch SET commit_id=? " "WHERE name=? AND repo_id=?", 3, "string", branch->commit_id, "string", branch->name, "string", branch->repo_id); else rc = seaf_db_statement_query (db, "INSERT INTO Branch VALUES (?, ?, ?)", 3, "string", branch->name, "string", branch->repo_id, "string", branch->commit_id); if (rc < 0) return -1; } else { int rc = seaf_db_statement_query (db, "REPLACE INTO Branch VALUES (?, ?, ?)", 3, "string", branch->name, "string", branch->repo_id, "string", branch->commit_id); if (rc < 0) return -1; } return 0; #endif }