/ Check-in [fed134a5]
Login

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

Overview
Comment:Add the sqlite3_db_readonly() API to trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: fed134a5f395533de0c9d76950697c060ddb126d
User & Date: drh 2012-03-15 22:54:37
Context
2012-03-16
00:28
Fix harmless compiler warnings. check-in: 74eadeec user: drh tags: trunk
2012-03-15
22:54
Add the sqlite3_db_readonly() API to trunk. check-in: fed134a5 user: drh tags: trunk
21:28
Add the sqlite3_db_readonly() interface. This is still tentative, pending a closer look at other ideas to accomplish the same thing. Closed-Leaf check-in: 254f99ea user: drh tags: db-readonly-api
2012-03-09
22:02
Candidate fix for the optimizer problem described in ticket [b7c8682cc17f3] which can causes a LEFT JOIN to be changed into a INNER JOIN if there are OR terms in the WHERE clause. check-in: 0dc4cb93 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/main.c.

2700
2701
2702
2703
2704
2705
2706
2707

2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
....
3022
3023
3024
3025
3026
3027
3028















3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040


3041




3042
}

/*
** Invoke the xFileControl method on a particular database.
*/
int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
  int rc = SQLITE_ERROR;
  int iDb;

  sqlite3_mutex_enter(db->mutex);
  if( zDbName==0 ){
    iDb = 0;
  }else{
    for(iDb=0; iDb<db->nDb; iDb++){
      if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break;
    }
  }
  if( iDb<db->nDb ){
    Btree *pBtree = db->aDb[iDb].pBt;
    if( pBtree ){
      Pager *pPager;
      sqlite3_file *fd;
      sqlite3BtreeEnter(pBtree);
      pPager = sqlite3BtreePager(pBtree);
      assert( pPager!=0 );
      fd = sqlite3PagerFile(pPager);
      assert( fd!=0 );
      if( op==SQLITE_FCNTL_FILE_POINTER ){
        *(sqlite3_file**)pArg = fd;
        rc = SQLITE_OK;
      }else if( fd->pMethods ){
        rc = sqlite3OsFileControl(fd, op, pArg);
      }else{
        rc = SQLITE_NOTFOUND;
      }
      sqlite3BtreeLeave(pBtree);
    }
  }
  sqlite3_mutex_leave(db->mutex);
  return rc;   
}

/*
** Interface to the testing logic.
................................................................................
  const char *z = sqlite3_uri_parameter(zFilename, zParam);
  sqlite3_int64 v;
  if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){
    bDflt = v;
  }
  return bDflt;
}
















/*
** Return the filename of the database associated with a database
** connection.
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
  int i;
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt && sqlite3StrICmp(zDbName, db->aDb[i].zName)==0 ){
      return sqlite3BtreeGetFilename(db->aDb[i].pBt);
    }
  }


  return 0;




}







|
>

<
|
<
<
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|
<
<
|
|
|
>
>
|
>
>
>
>

2700
2701
2702
2703
2704
2705
2706
2707
2708
2709

2710







2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727

2728
2729
2730
2731
2732
2733
2734
....
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042


3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
}

/*
** Invoke the xFileControl method on a particular database.
*/
int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
  int rc = SQLITE_ERROR;
  Btree *pBtree;

  sqlite3_mutex_enter(db->mutex);

  pBtree = sqlite3DbNameToBtree(db, zDbName);







  if( pBtree ){
    Pager *pPager;
    sqlite3_file *fd;
    sqlite3BtreeEnter(pBtree);
    pPager = sqlite3BtreePager(pBtree);
    assert( pPager!=0 );
    fd = sqlite3PagerFile(pPager);
    assert( fd!=0 );
    if( op==SQLITE_FCNTL_FILE_POINTER ){
      *(sqlite3_file**)pArg = fd;
      rc = SQLITE_OK;
    }else if( fd->pMethods ){
      rc = sqlite3OsFileControl(fd, op, pArg);
    }else{
      rc = SQLITE_NOTFOUND;
    }
    sqlite3BtreeLeave(pBtree);

  }
  sqlite3_mutex_leave(db->mutex);
  return rc;   
}

/*
** Interface to the testing logic.
................................................................................
  const char *z = sqlite3_uri_parameter(zFilename, zParam);
  sqlite3_int64 v;
  if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){
    bDflt = v;
  }
  return bDflt;
}

/*
** Return the Btree pointer identified by zDbName.  Return NULL if not found.
*/
Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
  int i;
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt
     && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
    ){
      return db->aDb[i].pBt;
    }
  }
  return 0;
}

/*
** Return the filename of the database associated with a database
** connection.
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
  Btree *pBt = sqlite3DbNameToBtree(db, zDbName);


  return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
}

/*
** Return 1 if database is read-only or 0 if read/write.  Return -1 if
** no such database exists.
*/
int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
  Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
  return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1;
}

Changes to src/sqlite.h.in.

4490
4491
4492
4493
4494
4495
4496









4497
4498
4499
4500
4501
4502
4503
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS].  ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);










/*
** CAPI3REF: Find the next prepared statement
**
** ^This interface returns a pointer to the next [prepared statement] after
** pStmt associated with the [database connection] pDb.  ^If pStmt is NULL
** then this interface returns a pointer to the first prepared statement
** associated with the database connection pDb.  ^If no prepared statement







>
>
>
>
>
>
>
>
>







4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS].  ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);

/*
** CAPI3REF: Determine if a database is read-only
**
** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
** the name of a database on connection D.
*/
int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);

/*
** CAPI3REF: Find the next prepared statement
**
** ^This interface returns a pointer to the next [prepared statement] after
** pStmt associated with the [database connection] pDb.  ^If pStmt is NULL
** then this interface returns a pointer to the first prepared statement
** associated with the database connection pDb.  ^If no prepared statement

Changes to src/sqliteInt.h.

2697
2698
2699
2700
2701
2702
2703

2704
2705
2706
2707
2708
2709
2710
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,ExprSpan*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
int sqlite3ParseUri(const char*,const char*,unsigned int*,
                    sqlite3_vfs**,char**,char **);

int sqlite3CodeOnce(Parse *);

Bitvec *sqlite3BitvecCreate(u32);
int sqlite3BitvecTest(Bitvec*, u32);
int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32, void*);
void sqlite3BitvecDestroy(Bitvec*);







>







2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,ExprSpan*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
int sqlite3ParseUri(const char*,const char*,unsigned int*,
                    sqlite3_vfs**,char**,char **);
Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
int sqlite3CodeOnce(Parse *);

Bitvec *sqlite3BitvecCreate(u32);
int sqlite3BitvecTest(Bitvec*, u32);
int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32, void*);
void sqlite3BitvecDestroy(Bitvec*);

Changes to src/test1.c.

4660
4661
4662
4663
4664
4665
4666
























4667
4668
4669
4670
4671
4672
4673
....
6051
6052
6053
6054
6055
6056
6057

6058
6059
6060
6061
6062
6063
6064
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zDbName = Tcl_GetString(objv[2]);
  Tcl_AppendResult(interp, sqlite3_db_filename(db, zDbName), (void*)0);
  return TCL_OK;
}

























/*
** Usage:  sqlite3_soft_heap_limit ?N?
**
** Query or set the soft heap limit for the current thread.  The
** limit is only changed if the N is present.  The previous limit
** is returned.
................................................................................
     { "sqlite3_stmt_readonly",         test_stmt_readonly ,0 },
     { "sqlite3_stmt_busy",             test_stmt_busy     ,0 },
     { "uses_stmt_journal",             uses_stmt_journal ,0 },

     { "sqlite3_release_memory",        test_release_memory,     0},
     { "sqlite3_db_release_memory",     test_db_release_memory,  0},
     { "sqlite3_db_filename",           test_db_filename,        0},

     { "sqlite3_soft_heap_limit",       test_soft_heap_limit,    0},
     { "sqlite3_thread_cleanup",        test_thread_cleanup,     0},
     { "sqlite3_pager_refcounts",       test_pager_refcounts,    0},

     { "sqlite3_load_extension",        test_load_extension,     0},
     { "sqlite3_enable_load_extension", test_enable_load,        0},
     { "sqlite3_extended_result_codes", test_extended_result_codes, 0},







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
....
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zDbName = Tcl_GetString(objv[2]);
  Tcl_AppendResult(interp, sqlite3_db_filename(db, zDbName), (void*)0);
  return TCL_OK;
}

/*
** Usage:  sqlite3_db_readonly DB DBNAME
**
** Return 1 or 0 if DBNAME is readonly or not.  Return -1 if DBNAME does
** not exist.
*/
static int test_db_readonly(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;
  const char *zDbName;
  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zDbName = Tcl_GetString(objv[2]);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_db_readonly(db, zDbName)));
  return TCL_OK;
}

/*
** Usage:  sqlite3_soft_heap_limit ?N?
**
** Query or set the soft heap limit for the current thread.  The
** limit is only changed if the N is present.  The previous limit
** is returned.
................................................................................
     { "sqlite3_stmt_readonly",         test_stmt_readonly ,0 },
     { "sqlite3_stmt_busy",             test_stmt_busy     ,0 },
     { "uses_stmt_journal",             uses_stmt_journal ,0 },

     { "sqlite3_release_memory",        test_release_memory,     0},
     { "sqlite3_db_release_memory",     test_db_release_memory,  0},
     { "sqlite3_db_filename",           test_db_filename,        0},
     { "sqlite3_db_readonly",           test_db_readonly,        0},
     { "sqlite3_soft_heap_limit",       test_soft_heap_limit,    0},
     { "sqlite3_thread_cleanup",        test_thread_cleanup,     0},
     { "sqlite3_pager_refcounts",       test_pager_refcounts,    0},

     { "sqlite3_load_extension",        test_load_extension,     0},
     { "sqlite3_enable_load_extension", test_enable_load,        0},
     { "sqlite3_extended_result_codes", test_extended_result_codes, 0},

Changes to test/pager1.test.

883
884
885
886
887
888
889


















890
891
892
893
894
895
896
do_test pager1.4.7.3 {
  db close
  catch {file attributes test.db-journal -permissions rw-rw-rw-}
  catch {file attributes test.db-journal -readonly 0}
  delete_file test.db-journal
  file exists test.db-journal
} {0}



















#-------------------------------------------------------------------------
# The following tests deal with multi-file commits.
#
# pager1-5.1.*: The case where a multi-file cannot be committed because
#               another connection is holding a SHARED lock on one of the
#               files. After the SHARED lock is removed, the COMMIT succeeds.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
do_test pager1.4.7.3 {
  db close
  catch {file attributes test.db-journal -permissions rw-rw-rw-}
  catch {file attributes test.db-journal -readonly 0}
  delete_file test.db-journal
  file exists test.db-journal
} {0}
do_test pager1.4.8.1 {
  catch {file attributes test.db -permissions r--------}
  catch {file attributes test.db -readonly 1}
  sqlite3 db test.db
  db eval { SELECT * FROM t1 }
  sqlite3_db_readonly db main
} {1}
do_test pager1.4.8.2 {
  sqlite3_db_readonly db xyz
} {-1}
do_test pager1.4.8.3 {
  db close
  catch {file attributes test.db -permissions rw-rw-rw-}
  catch {file attributes test.db -readonly 0}
  sqlite3 db test.db
  db eval { SELECT * FROM t1 }
  sqlite3_db_readonly db main
} {0}

#-------------------------------------------------------------------------
# The following tests deal with multi-file commits.
#
# pager1-5.1.*: The case where a multi-file cannot be committed because
#               another connection is holding a SHARED lock on one of the
#               files. After the SHARED lock is removed, the COMMIT succeeds.