SQLite

Check-in [441cabb62f]
Login

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

Overview
Comment:Add missing comments and fix other code issues in the new functions in callback.c.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | reuse-schema
Files: files | file ages | folders
SHA3-256: 441cabb62fe14bbef8b19066941426eeb2de128564ec2bfb762228fdae794447
User & Date: dan 2019-02-14 15:47:18.706
Context
2019-02-14
15:56
Merge latest trunk into this branch. (check-in: 577d163836 user: dan tags: reuse-schema)
15:47
Add missing comments and fix other code issues in the new functions in callback.c. (check-in: 441cabb62f user: dan tags: reuse-schema)
2019-02-13
19:17
Fix for sqlite3_table_column_metadata() on REUSE_SCHEMA databases. (check-in: 53220ad780 user: dan tags: reuse-schema)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/callback.c.
538
539
540
541
542
543
544




545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561





562
563
564
565
566








567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583



584
585
586
587
588
589
590
/*
** Global linked list of SchemaPool objects. Read and write access must
** be protected by the SQLITE_MUTEX_STATIC_MASTER mutex.
*/
static SchemaPool *SQLITE_WSD schemaPoolList = 0;

#ifdef SQLITE_TEST




SchemaPool *sqlite3SchemaPoolList(void){ return schemaPoolList; }
#endif

/*
** Check that the schema of db iDb is writable (either because it is the temp
** db schema or because the db handle was opened without
** SQLITE_OPEN_REUSE_SCHEMA). If so, do nothing. Otherwise, leave an 
** error in the Parse object.
*/
void sqlite3SchemaWritable(Parse *pParse, int iDb){
  if( iDb!=1 && (pParse->db->openFlags & SQLITE_OPEN_REUSE_SCHEMA) 
   && IN_DECLARE_VTAB==0
  ){
    sqlite3ErrorMsg(pParse, "attempt to modify read-only schema");
  }
}






static void schemaDelete(Schema *pSchema){
  sqlite3SchemaClear((void*)pSchema);
  sqlite3_free(pSchema);
}









static void schemaRelease(Db *pDb){
  assert( pDb->pSPool && pDb->pSchema );
  assert( pDb->pSchema->schemaFlags & DB_SchemaLoaded );
  assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) );

  pDb->pSchema->pNext = pDb->pSPool->pSchema;
  pDb->pSPool->pSchema = pDb->pSchema;
  pDb->pSchema = &pDb->pSPool->sSchema;

  assert( (pDb->pSchema->schemaFlags & DB_SchemaLoaded)==0 );
}

/*
** The schema for database iDb of database handle db, which was opened
** with SQLITE_OPEN_REUSE_SCHEMA, has just been parsed. This function either
** finds a matching SchemaPool object on the global list (schemaPoolList) or
** else allocates a new one and sets the Db.pSPool variable accordingly.



*/
int sqlite3SchemaConnect(sqlite3 *db, int iDb, u64 cksum){
  Schema *pSchema = db->aDb[iDb].pSchema;
  SchemaPool *p;

  assert( pSchema && iDb!=1 && db->aDb[iDb].pSPool==0 );








>
>
>
>




|
|











>
>
>
>
>





>
>
>
>
>
>
>
>

















>
>
>







538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
/*
** Global linked list of SchemaPool objects. Read and write access must
** be protected by the SQLITE_MUTEX_STATIC_MASTER mutex.
*/
static SchemaPool *SQLITE_WSD schemaPoolList = 0;

#ifdef SQLITE_TEST
/*
** Return a pointer to the head of the linked list of SchemaPool objects.
** This is used by the virtual table in file test_schemapool.c.
*/
SchemaPool *sqlite3SchemaPoolList(void){ return schemaPoolList; }
#endif

/*
** Check that the schema of db iDb is writable (either because it is the 
** temp db schema or because the db handle was opened without
** SQLITE_OPEN_REUSE_SCHEMA). If so, do nothing. Otherwise, leave an 
** error in the Parse object.
*/
void sqlite3SchemaWritable(Parse *pParse, int iDb){
  if( iDb!=1 && (pParse->db->openFlags & SQLITE_OPEN_REUSE_SCHEMA) 
   && IN_DECLARE_VTAB==0
  ){
    sqlite3ErrorMsg(pParse, "attempt to modify read-only schema");
  }
}

/*
** The schema object passed as the only argument was allocated using
** sqlite3_malloc() and then populated using the usual mechanism. This
** function frees both the Schema object and its contents.
*/
static void schemaDelete(Schema *pSchema){
  sqlite3SchemaClear((void*)pSchema);
  sqlite3_free(pSchema);
}

/*
** When this function is called, the database connection Db must be
** using a schema-pool (Db.pSPool!=0) and must currently have Db.pSchema
** set to point to a populated schema object checked out from the 
** schema-pool. It is also assumed that the STATIC_MASTER mutex is held.
** This function returns the Schema object to the schema-pool and sets
** Db.pSchema to point to the schema-pool's static, empty, Schema object.
*/
static void schemaRelease(Db *pDb){
  assert( pDb->pSPool && pDb->pSchema );
  assert( pDb->pSchema->schemaFlags & DB_SchemaLoaded );
  assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) );

  pDb->pSchema->pNext = pDb->pSPool->pSchema;
  pDb->pSPool->pSchema = pDb->pSchema;
  pDb->pSchema = &pDb->pSPool->sSchema;

  assert( (pDb->pSchema->schemaFlags & DB_SchemaLoaded)==0 );
}

/*
** The schema for database iDb of database handle db, which was opened
** with SQLITE_OPEN_REUSE_SCHEMA, has just been parsed. This function either
** finds a matching SchemaPool object on the global list (schemaPoolList) or
** else allocates a new one and sets the Db.pSPool variable accordingly.
**
** SQLITE_OK is returned if no error occurs, or an SQLite error code 
** (SQLITE_NOMEM) otherwise.
*/
int sqlite3SchemaConnect(sqlite3 *db, int iDb, u64 cksum){
  Schema *pSchema = db->aDb[iDb].pSchema;
  SchemaPool *p;

  assert( pSchema && iDb!=1 && db->aDb[iDb].pSPool==0 );

625
626
627
628
629
630
631















632
633
634
635
636
637
638

  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );

  db->aDb[iDb].pSPool = p;
  return (p ? SQLITE_OK : SQLITE_NOMEM);
}
















int sqlite3SchemaDisconnect(sqlite3 *db, int iDb, int bNew){
  int rc = SQLITE_OK;
  if( IsReuseSchema(db) && iDb!=1 ){
    Db *pDb = &db->aDb[iDb];
    SchemaPool *pSPool = pDb->pSPool;
    assert_schema_state_ok(db);
    assert( pDb->pSchema );







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







645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );

  db->aDb[iDb].pSPool = p;
  return (p ? SQLITE_OK : SQLITE_NOMEM);
}

/*
** If parameter iDb is 1 (the temp db), or if connection handle db was not
** opened with the SQLITE_OPEN_REUSE_SCHEMA flag, this function is a no-op.
** Otherwise, it disconnects from the schema-pool associated with database
** iDb, assuming it is connected.
**
** If parameter bNew is true, then Db.pSchema is set to point to a new, empty,
** Schema object obtained from sqlite3_malloc(). Or, if bNew is false, then
** Db.pSchema is set to NULL before returning.
**
** If the bNew parameter is true, then this function may allocate memory. 
** If the allocation attempt fails, then SQLITE_NOMEM is returned and the
** schema-pool is not disconnected from. Or, if no OOM error occurs, 
** SQLITE_OK is returned.
*/
int sqlite3SchemaDisconnect(sqlite3 *db, int iDb, int bNew){
  int rc = SQLITE_OK;
  if( IsReuseSchema(db) && iDb!=1 ){
    Db *pDb = &db->aDb[iDb];
    SchemaPool *pSPool = pDb->pSPool;
    assert_schema_state_ok(db);
    assert( pDb->pSchema );
700
701
702
703
704
705
706





707
708
709
710
711
712
713
714
715
716
717
718
719
720
721





722
723
724
725
726
727
728
729
730
731
732
733
734
735



736
737
738
739
740
741
742
      pRet->pNext = 0;
    }
    sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  }
  return pRet;
}






void sqlite3SchemaReleaseAll(sqlite3 *db){
  int i;
  assert_schema_state_ok(db);
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  for(i=0; i<db->nDb; i++){
    if( i!=1 ){
      Db *pDb = &db->aDb[i];
      if( pDb->pSPool && DbHasProperty(db,i,DB_SchemaLoaded) ){
        schemaRelease(pDb);
      }
    }
  }
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}






void sqlite3SchemaRelease(sqlite3 *db, int iDb){
  Db *pDb = &db->aDb[iDb];
  assert( iDb!=1 );
  assert_schema_state_ok(db);
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  if( pDb->pSPool && DbHasProperty(db, iDb, DB_SchemaLoaded) ){
    schemaRelease(pDb);
  }
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}

/*
** Find and return the schema associated with a BTree.  Create
** a new one if necessary.



*/
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
  Schema *p;
  if( pBt && (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA)==0 ){
    p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
  }else{
    p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));







>
>
>
>
>















>
>
>
>
>












|
|
>
>
>







735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
      pRet->pNext = 0;
    }
    sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  }
  return pRet;
}

/*
** Return all sharable schemas held by database handle db back to their
** respective schema-pools. Db.pSchema variables are left pointing to
** the static, empty, Schema object owned by each schema-pool.
*/
void sqlite3SchemaReleaseAll(sqlite3 *db){
  int i;
  assert_schema_state_ok(db);
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  for(i=0; i<db->nDb; i++){
    if( i!=1 ){
      Db *pDb = &db->aDb[i];
      if( pDb->pSPool && DbHasProperty(db,i,DB_SchemaLoaded) ){
        schemaRelease(pDb);
      }
    }
  }
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}

/*
** Release any sharable schema held by connection iDb of database handle
** db. Db.pSchema is left pointing to the static, empty, Schema object
** owned by the schema-pool.
*/
void sqlite3SchemaRelease(sqlite3 *db, int iDb){
  Db *pDb = &db->aDb[iDb];
  assert( iDb!=1 );
  assert_schema_state_ok(db);
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  if( pDb->pSPool && DbHasProperty(db, iDb, DB_SchemaLoaded) ){
    schemaRelease(pDb);
  }
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}

/*
** In most cases, this function finds and returns the schema associated 
** with BTree handle pBt, creating a new one if necessary. However, if
** the database handle was opened with the SQLITE_OPEN_REUSE_SCHEMA flag
** specified, a new, empty, Schema object in memory obtained by 
** sqlite3_malloc() is always returned.
*/
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
  Schema *p;
  if( pBt && (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA)==0 ){
    p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
  }else{
    p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
Changes to test/reuse1.test.
84
85
86
87
88
89
90

91
92
93
94
95
96
97
  4  { ALTER TABLE t1 RENAME TO t3 }
  5  { ALTER TABLE t1 ADD COLUMN xyz }
  6  { VACUUM }
  7  { DROP INDEX i1 }
  8  { DROP TABLE t1 }
  9  { DROP TRIGGER tr1 }
  10 { ANALYZE }

} {
  do_catchsql_test 1.5.$tn $sql {1 {attempt to modify read-only schema}}
}

#-------------------------------------------------------------------------
#
reset_db







>







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  4  { ALTER TABLE t1 RENAME TO t3 }
  5  { ALTER TABLE t1 ADD COLUMN xyz }
  6  { VACUUM }
  7  { DROP INDEX i1 }
  8  { DROP TABLE t1 }
  9  { DROP TRIGGER tr1 }
  10 { ANALYZE }
  11 { ALTER TABLE t1 RENAME z TO zzz }
} {
  do_catchsql_test 1.5.$tn $sql {1 {attempt to modify read-only schema}}
}

#-------------------------------------------------------------------------
#
reset_db