/ Check-in [ba92af18]
Login

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

Overview
Comment:Make sure the in-memory database can handle malloc failures. (CVS 1169)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:ba92af182c6c9c6b2e3816006191eedd424cdf1a
User & Date: drh 2004-01-12 00:21:52
Context
2004-01-12
00:38
Previous commit of changes to the in-memory backend was not quite right. This check-in should square things away. (CVS 1170) check-in: 75d91e3b user: drh tags: trunk
00:21
Make sure the in-memory database can handle malloc failures. (CVS 1169) check-in: ba92af18 user: drh tags: trunk
2004-01-08
02:17
Remove unused code and tighten existing code to make the library a little smaller. (CVS 1168) check-in: 34a6b741 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree_rb.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
614
615
616
617
618
619
620

621
622
623
624

625
626
627
628
629
630
631
632




633
634
635
636
637
638
639
640
641
642
643
644

645
646
647
648
649

650
651
652
653
654
655
656
...
667
668
669
670
671
672
673

674
675
676
677
678
679
680
...
708
709
710
711
712
713
714

715
716
717
718
719
720
721
...
751
752
753
754
755
756
757

758
759
760
761
762
763
764
...
767
768
769
770
771
772
773

774
775

776
777
778
779
780
781
782
...
800
801
802
803
804
805
806

807
808
809
810

811
812
813
814
815
816
817
818
819
820
821

822
823
824

825
826
827
828
829
830
831
...
920
921
922
923
924
925
926

927
928
929
930
931
932
933
....
1025
1026
1027
1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree_rb.c,v 1.18 2003/12/06 21:43:56 drh Exp $
**
** This file implements an in-core database using Red-Black balanced
** binary trees.
** 
** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
*/
#include "btree.h"
................................................................................
  const char *zFilename,
  int mode,
  int nPg,
  Btree **ppBtree
){
  Rbtree **ppRbtree = (Rbtree**)ppBtree;
  *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree));

  sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0);

  /* Create a binary tree for the SQLITE_MASTER table at location 2 */
  btreeCreateTable(*ppRbtree, 2);

  (*ppRbtree)->next_idx = 3;
  (*ppRbtree)->pOps = &sqliteRbtreeOps;
  /* Set file type to 4; this is so that "attach ':memory:' as ...."  does not
  ** think that the database in uninitialised and refuse to attach
  */
  (*ppRbtree)->aMetaData[2] = 4;
  
  return SQLITE_OK;




}

/*
 * Create a new table in the supplied Rbtree. Set *n to the new table number.
 * Return SQLITE_OK if the operation is a success.
 */
static int memRbtreeCreateTable(Rbtree* tree, int* n)
{
  assert( tree->eTransState != TRANS_NONE );

  *n = tree->next_idx++;
  btreeCreateTable(tree, *n);


  /* Set up the rollback structure (if we are not doing this as part of a
   * rollback) */
  if( tree->eTransState != TRANS_ROLLBACK ){
    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));

    pRollbackOp->eOp = ROLLBACK_DROP;
    pRollbackOp->iTab = *n;
    btreeLogRollbackOp(tree, pRollbackOp);
  }

  return SQLITE_OK;
}
................................................................................
  pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
  assert(pTree);
  assert( pTree->pCursors==0 );
  sqliteFree(pTree);

  if( tree->eTransState != TRANS_ROLLBACK ){
    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));

    pRollbackOp->eOp = ROLLBACK_CREATE;
    pRollbackOp->iTab = n;
    btreeLogRollbackOp(tree, pRollbackOp);
  }

  return SQLITE_OK;
}
................................................................................
  int iTable,
  int wrFlag,
  RbtCursor **ppCur
){
  RbtCursor *pCur;
  assert(tree);
  pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor));

  pCur->pTree  = sqliteHashFind(&tree->tblHash, 0, iTable);
  pCur->pRbtree = tree;
  pCur->iTree  = iTable;
  pCur->pOps = &sqliteRbtreeCursorOps;
  pCur->wrFlag = wrFlag;
  pCur->pShared = pCur->pTree->pCursors;
  pCur->pTree->pCursors = pCur;
................................................................................
  if( checkReadLocks(pCur) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }

  /* Take a copy of the input data now, in case we need it for the 
   * replace case */
  pData = sqliteMallocRaw(nData);

  memcpy(pData, pDataInput, nData);

  /* Move the cursor to a node near the key to be inserted. If the key already
   * exists in the table, then (match == 0). In this case we can just replace
   * the data associated with the entry, we don't need to manipulate the tree.
   * 
   * If there is no exact match, then the cursor points at what would be either
................................................................................
   * this node.
   * 
   * The new node is initially red.
   */
  memRbtreeMoveto( pCur, pKey, nKey, &match);
  if( match ){
    BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));

    pNode->nKey = nKey;
    pNode->pKey = sqliteMallocRaw(nKey);

    memcpy(pNode->pKey, pKey, nKey);
    pNode->nData = nData;
    pNode->pData = pData; 
    if( pCur->pNode ){
      switch( match ){
        case -1:
          assert( !pCur->pNode->pRight );
................................................................................

    /* A new node has just been inserted, so run the balancing code */
    do_insert_balancing(pCur->pTree, pNode);

    /* Set up a rollback-op in case we have to roll this operation back */
    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );

      pOp->eOp = ROLLBACK_DELETE;
      pOp->iTab = pCur->iTree;
      pOp->nKey = pNode->nKey;
      pOp->pKey = sqliteMallocRaw( pOp->nKey );

      memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
      btreeLogRollbackOp(pCur->pRbtree, pOp);
    }

  }else{ 
    /* No need to insert a new node in the tree, as the key already exists.
     * Just clobber the current nodes data. */

    /* Set up a rollback-op in case we have to roll this operation back */
    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );

      pOp->iTab = pCur->iTree;
      pOp->nKey = pCur->pNode->nKey;
      pOp->pKey = sqliteMallocRaw( pOp->nKey );

      memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey );
      pOp->nData = pCur->pNode->nData;
      pOp->pData = pCur->pNode->pData;
      pOp->eOp = ROLLBACK_INSERT;
      btreeLogRollbackOp(pCur->pRbtree, pOp);
    }else{
      sqliteFree( pCur->pNode->pData );
................................................................................
    return SQLITE_OK;
  }

  /* If we are not currently doing a rollback, set up a rollback op for this 
   * deletion */
  if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
    BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );

    pOp->iTab = pCur->iTree;
    pOp->nKey = pZ->nKey;
    pOp->pKey = pZ->pKey;
    pOp->nData = pZ->nData;
    pOp->pData = pZ->pData;
    pOp->eOp = ROLLBACK_INSERT;
    btreeLogRollbackOp(pCur->pRbtree, pOp);
................................................................................
    else {
      BtRbNode *pTmp = pNode->pParent;
      if( tree->eTransState == TRANS_ROLLBACK ){
        sqliteFree( pNode->pKey );
        sqliteFree( pNode->pData );
      }else{
        BtRollbackOp *pRollbackOp = sqliteMallocRaw(sizeof(BtRollbackOp));

        pRollbackOp->eOp = ROLLBACK_INSERT;
        pRollbackOp->iTab = n;
        pRollbackOp->nKey = pNode->nKey;
        pRollbackOp->pKey = pNode->pKey;
        pRollbackOp->nData = pNode->nData;
        pRollbackOp->pData = pNode->pData;
        btreeLogRollbackOp(tree, pRollbackOp);







|







 







>




>








>
>
>
>












>





>







 







>







 







>







 







>







 







>


>







 







>




>











>



>







 







>







 







>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
...
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
...
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
...
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
...
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
...
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
....
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree_rb.c,v 1.19 2004/01/12 00:21:52 drh Exp $
**
** This file implements an in-core database using Red-Black balanced
** binary trees.
** 
** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
*/
#include "btree.h"
................................................................................
  const char *zFilename,
  int mode,
  int nPg,
  Btree **ppBtree
){
  Rbtree **ppRbtree = (Rbtree**)ppBtree;
  *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree));
  if( sqlite_malloc_failed ) goto open_no_mem;
  sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0);

  /* Create a binary tree for the SQLITE_MASTER table at location 2 */
  btreeCreateTable(*ppRbtree, 2);
  if( sqlite_malloc_failed ) goto open_no_mem;
  (*ppRbtree)->next_idx = 3;
  (*ppRbtree)->pOps = &sqliteRbtreeOps;
  /* Set file type to 4; this is so that "attach ':memory:' as ...."  does not
  ** think that the database in uninitialised and refuse to attach
  */
  (*ppRbtree)->aMetaData[2] = 4;
  
  return SQLITE_OK;

open_no_mem:
  *ppBtree = 0;
  return SQLITE_NOMEM;
}

/*
 * Create a new table in the supplied Rbtree. Set *n to the new table number.
 * Return SQLITE_OK if the operation is a success.
 */
static int memRbtreeCreateTable(Rbtree* tree, int* n)
{
  assert( tree->eTransState != TRANS_NONE );

  *n = tree->next_idx++;
  btreeCreateTable(tree, *n);
  if( sqlite_malloc_failed ) return SQLITE_NOMEM;

  /* Set up the rollback structure (if we are not doing this as part of a
   * rollback) */
  if( tree->eTransState != TRANS_ROLLBACK ){
    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
    if( pRollbackOp==0 ) return SQLITE_NOMEM;
    pRollbackOp->eOp = ROLLBACK_DROP;
    pRollbackOp->iTab = *n;
    btreeLogRollbackOp(tree, pRollbackOp);
  }

  return SQLITE_OK;
}
................................................................................
  pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
  assert(pTree);
  assert( pTree->pCursors==0 );
  sqliteFree(pTree);

  if( tree->eTransState != TRANS_ROLLBACK ){
    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
    if( pRollbackOp==0 ) return SQLITE_NOMEM;
    pRollbackOp->eOp = ROLLBACK_CREATE;
    pRollbackOp->iTab = n;
    btreeLogRollbackOp(tree, pRollbackOp);
  }

  return SQLITE_OK;
}
................................................................................
  int iTable,
  int wrFlag,
  RbtCursor **ppCur
){
  RbtCursor *pCur;
  assert(tree);
  pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor));
  if( sqlite_malloc_failed ) return SQLITE_NOMEM;
  pCur->pTree  = sqliteHashFind(&tree->tblHash, 0, iTable);
  pCur->pRbtree = tree;
  pCur->iTree  = iTable;
  pCur->pOps = &sqliteRbtreeCursorOps;
  pCur->wrFlag = wrFlag;
  pCur->pShared = pCur->pTree->pCursors;
  pCur->pTree->pCursors = pCur;
................................................................................
  if( checkReadLocks(pCur) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }

  /* Take a copy of the input data now, in case we need it for the 
   * replace case */
  pData = sqliteMallocRaw(nData);
  if( pData==0 ) return SQLITE_NOMEM;
  memcpy(pData, pDataInput, nData);

  /* Move the cursor to a node near the key to be inserted. If the key already
   * exists in the table, then (match == 0). In this case we can just replace
   * the data associated with the entry, we don't need to manipulate the tree.
   * 
   * If there is no exact match, then the cursor points at what would be either
................................................................................
   * this node.
   * 
   * The new node is initially red.
   */
  memRbtreeMoveto( pCur, pKey, nKey, &match);
  if( match ){
    BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));
    if( pNode==0 ) return SQLITE_NOMEM;
    pNode->nKey = nKey;
    pNode->pKey = sqliteMallocRaw(nKey);
    if( pNode->pKey==0 ) return SQLITE_NOMEM;
    memcpy(pNode->pKey, pKey, nKey);
    pNode->nData = nData;
    pNode->pData = pData; 
    if( pCur->pNode ){
      switch( match ){
        case -1:
          assert( !pCur->pNode->pRight );
................................................................................

    /* A new node has just been inserted, so run the balancing code */
    do_insert_balancing(pCur->pTree, pNode);

    /* Set up a rollback-op in case we have to roll this operation back */
    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
      if( pOp==0 ) return SQLITE_NOMEM;
      pOp->eOp = ROLLBACK_DELETE;
      pOp->iTab = pCur->iTree;
      pOp->nKey = pNode->nKey;
      pOp->pKey = sqliteMallocRaw( pOp->nKey );
      if( pOp->pKey==0 ) return SQLITE_NOMEM;
      memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
      btreeLogRollbackOp(pCur->pRbtree, pOp);
    }

  }else{ 
    /* No need to insert a new node in the tree, as the key already exists.
     * Just clobber the current nodes data. */

    /* Set up a rollback-op in case we have to roll this operation back */
    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
      if( pOp==0 ) return SQLITE_NOMEM;
      pOp->iTab = pCur->iTree;
      pOp->nKey = pCur->pNode->nKey;
      pOp->pKey = sqliteMallocRaw( pOp->nKey );
      if( pOp->pKey==0 ) return SQLITE_NOMEM;
      memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey );
      pOp->nData = pCur->pNode->nData;
      pOp->pData = pCur->pNode->pData;
      pOp->eOp = ROLLBACK_INSERT;
      btreeLogRollbackOp(pCur->pRbtree, pOp);
    }else{
      sqliteFree( pCur->pNode->pData );
................................................................................
    return SQLITE_OK;
  }

  /* If we are not currently doing a rollback, set up a rollback op for this 
   * deletion */
  if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
    BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
    if( pOp==0 ) return SQLITE_NOMEM;
    pOp->iTab = pCur->iTree;
    pOp->nKey = pZ->nKey;
    pOp->pKey = pZ->pKey;
    pOp->nData = pZ->nData;
    pOp->pData = pZ->pData;
    pOp->eOp = ROLLBACK_INSERT;
    btreeLogRollbackOp(pCur->pRbtree, pOp);
................................................................................
    else {
      BtRbNode *pTmp = pNode->pParent;
      if( tree->eTransState == TRANS_ROLLBACK ){
        sqliteFree( pNode->pKey );
        sqliteFree( pNode->pData );
      }else{
        BtRollbackOp *pRollbackOp = sqliteMallocRaw(sizeof(BtRollbackOp));
        if( pRollbackOp==0 ) return SQLITE_NOMEM;
        pRollbackOp->eOp = ROLLBACK_INSERT;
        pRollbackOp->iTab = n;
        pRollbackOp->nKey = pNode->nKey;
        pRollbackOp->pKey = pNode->pKey;
        pRollbackOp->nData = pNode->nData;
        pRollbackOp->pData = pNode->pData;
        btreeLogRollbackOp(tree, pRollbackOp);