1   /*
2   Copyright (c) 2008 Health Market Science, Inc.
3   
4   This library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8   
9   This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Lesser General Public License for more details.
13  
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17  USA
18  
19  You can contact Health Market Science at info@healthmarketscience.com
20  or at the following address:
21  
22  Health Market Science
23  2700 Horizon Drive
24  Suite 200
25  King of Prussia, PA 19406
26  */
27  
28  package com.healthmarketscience.jackcess;
29  
30  import java.io.File;
31  import java.util.ArrayList;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Random;
35  
36  import junit.framework.TestCase;
37  
38  import static com.healthmarketscience.jackcess.DatabaseTest.*;
39  
40  
41  /**
42   * @author james
43   */
44  public class BigIndexTest extends TestCase {
45  
46    private String _oldBigIndexValue = null;
47    
48    /**
49     * Creates a new <code>IndexTest</code> instance.
50     *
51     */
52    public BigIndexTest(String name) {
53      super(name);
54    }
55  
56    @Override
57    protected void setUp() {
58      _oldBigIndexValue = System.getProperty(Database.USE_BIG_INDEX_PROPERTY);
59      System.setProperty(Database.USE_BIG_INDEX_PROPERTY,
60                         Boolean.TRUE.toString());
61    }
62    
63    @Override
64    protected void tearDown() {
65      System.setProperty(Database.USE_BIG_INDEX_PROPERTY, _oldBigIndexValue);
66    }
67    
68    public void testComplexIndex() throws Exception
69    {
70      // this file has an index with "compressed" entries and node pages
71      Database db = open(new File("test/data/compIndexTest.mdb"));
72      Table t = db.getTable("Table1");
73      Index index = t.getIndex("CD_AGENTE");
74      assertFalse(index.isInitialized());
75      assertEquals(512, countRows(t));
76      assertEquals(512, index.getEntryCount());
77      db.close();
78    }
79  
80    public void testBigIndex() throws Exception
81    {
82      // this file has an index with "compressed" entries and node pages
83      File origFile = new File("test/data/bigIndexTest.mdb");
84      Database db = open(origFile);
85      Table t = db.getTable("Table1");
86      Index index = t.getIndex("col1");
87      assertFalse(index.isInitialized());
88      assertEquals(0, countRows(t));
89      assertEquals(0, index.getEntryCount());
90      db.close();
91  
92      DatabaseTest._autoSync = false;
93      try {
94  
95        String extraText = " some random text to fill out the index and make it fill up pages with lots of extra bytes so i will keep typing until i think that i probably have enough text in the index entry so that i do not need to add as many entries in order";
96        
97        // copy to temp file and attempt to edit
98        db = openCopy(origFile);
99        t = db.getTable("Table1");
100       index = t.getIndex("col1");
101 
102       System.out.println("BigIndexTest: Index type: " + index.getClass());
103 
104       // add 2,000 (pseudo) random entries to the table
105       Random rand = new Random(13L);
106       for(int i = 0; i < 2000; ++i) {
107         if((i == 850) || (i == 1850)) {
108           int end = i + 50;
109           List<Object[]> rows = new ArrayList<Object[]>(50);
110           for(; i < end; ++i) {
111             int nextInt = rand.nextInt(Integer.MAX_VALUE);
112             String nextVal = "" + nextInt + extraText;
113             if(((i + 1) % 333) == 0) {
114               nextVal = null;
115             }
116             rows.add(new Object[]{nextVal,
117                                   "this is some row data " + nextInt});
118           }
119           t.addRows(rows);
120           --i;
121         } else {
122           int nextInt = rand.nextInt(Integer.MAX_VALUE);
123           String nextVal = "" + nextInt + extraText;
124           if(((i + 1) % 333) == 0) {
125             nextVal = null;
126           }
127           t.addRow(nextVal, "this is some row data " + nextInt);
128         }
129       }
130 
131       ((BigIndex)index).validate();
132       
133       db.flush();
134       t = db.getTable("Table1");
135       index = t.getIndex("col1");
136 
137       // make sure all entries are there and correctly ordered
138       String firstValue = "      ";
139       String prevValue = firstValue;
140       int rowCount = 0;
141       List<String> firstTwo = new ArrayList<String>();
142       for(Map<String,Object> row : Cursor.createIndexCursor(t, index)) {
143         String origVal = (String)row.get("col1");
144         String val = origVal;
145         if(val == null) {
146           val = firstValue;
147         }
148         assertTrue("" + prevValue + " <= " + val + " " + rowCount,
149                    prevValue.compareTo(val) <= 0);
150         if(firstTwo.size() < 2) {
151           firstTwo.add(origVal);
152         }
153         prevValue = val;
154         ++rowCount;
155       }
156 
157       assertEquals(2000, rowCount);
158 
159       ((BigIndex)index).validate();
160       
161       // delete an entry in the middle
162       Cursor cursor = Cursor.createIndexCursor(t, index);
163       for(int i = 0; i < (rowCount / 2); ++i) {
164         assertTrue(cursor.moveToNextRow());
165       }
166       cursor.deleteCurrentRow();
167       --rowCount;
168       
169       // remove all but the first two entries (from the end)
170       cursor.afterLast();
171       for(int i = 0; i < (rowCount - 2); ++i) {
172         assertTrue(cursor.moveToPreviousRow());
173         cursor.deleteCurrentRow();
174       }
175 
176       ((BigIndex)index).validate();
177       
178       List<String> found = new ArrayList<String>();
179       for(Map<String,Object> row : Cursor.createIndexCursor(t, index)) {
180         found.add((String)row.get("col1"));
181       }      
182 
183       assertEquals(firstTwo, found);
184 
185       // remove remaining entries
186       cursor = Cursor.createCursor(t);
187       for(int i = 0; i < 2; ++i) {
188         assertTrue(cursor.moveToNextRow());
189         cursor.deleteCurrentRow();
190       }
191 
192       assertFalse(cursor.moveToNextRow());
193       assertFalse(cursor.moveToPreviousRow());
194       
195       ((BigIndex)index).validate();
196 
197       // add 50 (pseudo) random entries to the table
198       rand = new Random(42L);
199       for(int i = 0; i < 50; ++i) {
200         int nextInt = rand.nextInt(Integer.MAX_VALUE);
201         String nextVal = "some prefix " + nextInt + extraText;
202         if(((i + 1) % 3333) == 0) {
203           nextVal = null;
204         }
205         t.addRow(nextVal, "this is some row data " + nextInt);
206       }
207 
208       ((BigIndex)index).validate();
209 
210       cursor = Cursor.createIndexCursor(t, index);
211       while(cursor.moveToNextRow()) {
212         cursor.deleteCurrentRow();
213       }
214       
215       ((BigIndex)index).validate();
216       
217       db.close();
218       
219     } finally {
220       DatabaseTest._autoSync = Database.DEFAULT_AUTO_SYNC;
221     }
222   }
223 
224 }