1#!/usr/bin/env python
2#
3# Public Domain 2014-2018 MongoDB, Inc.
4# Public Domain 2008-2014 WiredTiger, Inc.
5#
6# This is free and unencumbered software released into the public domain.
7#
8# Anyone is free to copy, modify, publish, use, compile, sell, or
9# distribute this software, either in source code form or as a compiled
10# binary, for any purpose, commercial or non-commercial, and by any
11# means.
12#
13# In jurisdictions that recognize copyright laws, the author or authors
14# of this software dedicate any and all copyright interest in the
15# software to the public domain. We make this dedication for the benefit
16# of the public at large and to the detriment of our heirs and
17# successors. We intend this dedication to be an overt act of
18# relinquishment in perpetuity of all present and future rights to this
19# software under copyright law.
20#
21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27# OTHER DEALINGS IN THE SOFTWARE.
28
29import wiredtiger, wttest
30
31# test_index01.py
32#    basic tests for indices
33class test_index01(wttest.WiredTigerTestCase):
34    '''Test basic operations for indices'''
35
36    basename = 'test_index01'
37    tablename = 'table:' + basename
38    indexbase = 'index:' + basename
39    NUM_INDICES = 6
40    index = ['%s:index%d' % (indexbase, i) for i in xrange(NUM_INDICES)]
41
42    def create_table(self):
43        self.pr('create table')
44        self.session.create(self.tablename, 'key_format=Si,value_format=SSii,columns=(name,ID,dept,job,salary,year)')
45        self.session.create(self.index[0], 'columns=(dept)')
46        self.session.create(self.index[1], 'columns=(name,year)')
47        self.session.create(self.index[2], 'columns=(salary)')
48        self.session.create(self.index[3], 'columns=(dept,job,name)')
49        self.session.create(self.index[4], 'columns=(name,ID)')
50        self.session.create(self.index[5], 'columns=(ID,name)')
51
52    def drop_table(self):
53        self.pr('drop table')
54        self.session.drop(self.tablename, None)
55
56    def cursor(self, config=None):
57        self.pr('open cursor')
58        c = self.session.open_cursor(self.tablename, None, config)
59        self.assertNotEqual(c, None)
60        return c
61
62    def index_cursor(self, i):
63        self.pr('open index cursor(%d)' % i)
64        c = self.session.open_cursor(self.index[i], None, None)
65        self.assertNotEqual(c, None)
66        return c
67
68    def index_iter(self, i):
69        cursor = self.index_cursor(i)
70        for cols in cursor:
71            yield cols
72        cursor.close()
73
74    def check_exists(self, name, ID, expected):
75        cursor = self.cursor()
76        cursor.set_key(name, ID)
77        self.pr('search')
78        self.assertEqual(cursor.search(), expected)
79        self.pr('closing cursor')
80        cursor.close()
81
82    def insert(self, *cols):
83        self.pr('insert')
84        cursor = self.cursor(config='overwrite=false')
85        cursor.set_key(*cols[:2])
86        cursor.set_value(*cols[2:])
87        self.assertEqual(cursor.insert(), 0)
88        cursor.close()
89
90    def insert_duplicate(self, *cols):
91        self.pr('insert')
92        cursor = self.cursor(config='overwrite=false')
93        cursor.set_key(*cols[:2])
94        cursor.set_value(*cols[2:])
95        self.assertRaises(wiredtiger.WiredTigerError, lambda: cursor.insert())
96        cursor.close()
97
98    def insert_overwrite(self, *cols):
99        self.pr('insert')
100        cursor = self.cursor(config='overwrite=true')
101        cursor.set_key(*cols[:2])
102        cursor.set_value(*cols[2:])
103        self.assertEqual(cursor.insert(), 0)
104        cursor.close()
105
106    def update(self, *cols):
107        self.pr('update')
108        cursor = self.cursor(config='overwrite=false')
109        cursor.set_key(*cols[:2])
110        cursor.set_value(*cols[2:])
111        self.assertEqual(cursor.update(), 0)
112        cursor.close()
113
114    def update_nonexistent(self, *cols):
115        self.pr('update')
116        cursor = self.cursor(config='overwrite=false')
117        cursor.set_key(*cols[:2])
118        cursor.set_value(*cols[2:])
119        self.assertEqual(cursor.update(), wiredtiger.WT_NOTFOUND)
120        cursor.close()
121
122    def remove(self, name, ID):
123        self.pr('remove')
124        cursor = self.cursor(config='overwrite=false')
125        cursor.set_key(name, ID)
126        self.assertEqual(cursor.remove(), 0)
127        cursor.close()
128
129    def test_empty(self):
130        '''Create a table, look for a nonexistent key'''
131        self.create_table()
132        self.check_exists('jones', 10, wiredtiger.WT_NOTFOUND)
133        for i in xrange(self.NUM_INDICES):
134            self.assertEqual(list(self.index_iter(i)), [])
135        self.drop_table()
136
137    def test_insert(self):
138        '''Create a table, add a key, get it back'''
139        self.create_table()
140        self.insert('smith', 1, 'HR', 'manager', 100000, 1970)
141        self.check_exists('smith', 1, 0)
142        result = ''
143        for i in xrange(self.NUM_INDICES):
144            result += '\n'.join(repr(cols)
145                for cols in self.index_iter(i))
146            result += '\n\n'
147        self.assertEqual(result, \
148            "['HR', 'HR', 'manager', 100000, 1970]\n\n" + \
149            "['smith', 1970, 'HR', 'manager', 100000, 1970]\n\n" + \
150            "[100000, 'HR', 'manager', 100000, 1970]\n\n" + \
151            "['HR', 'manager', 'smith', 'HR', 'manager', 100000, 1970]\n\n" + \
152            "['smith', 1, 'HR', 'manager', 100000, 1970]\n\n" + \
153            "[1, 'smith', 'HR', 'manager', 100000, 1970]\n\n")
154        self.drop_table()
155
156    def test_update(self):
157        '''Create a table, add a key, update it, get it back'''
158        self.create_table()
159        self.insert('smith', 1, 'HR', 'manager', 100000, 1970)
160        self.update('smith', 1, 'HR', 'janitor', 10000, 1970)
161        self.update_nonexistent('smith', 2, 'HR', 'janitor', 1000, 1970)
162        self.update_nonexistent('Smith', 1, 'HR', 'janitor', 1000, 1970)
163        self.check_exists('smith', 1, 0)
164        result = ''
165        for i in xrange(self.NUM_INDICES):
166            result += '\n'.join(repr(cols)
167                for cols in self.index_iter(i))
168            result += '\n\n'
169        self.assertEqual(result, \
170            "['HR', 'HR', 'janitor', 10000, 1970]\n\n" + \
171            "['smith', 1970, 'HR', 'janitor', 10000, 1970]\n\n" + \
172            "[10000, 'HR', 'janitor', 10000, 1970]\n\n" + \
173            "['HR', 'janitor', 'smith', 'HR', 'janitor', 10000, 1970]\n\n" + \
174            "['smith', 1, 'HR', 'janitor', 10000, 1970]\n\n" + \
175            "[1, 'smith', 'HR', 'janitor', 10000, 1970]\n\n")
176        self.drop_table()
177
178    def test_insert_overwrite(self):
179        '''Create a table, add a key, insert-overwrite it,
180           insert-overwrite a nonexistent record, get them both back'''
181        self.create_table()
182        self.insert('smith', 1, 'HR', 'manager', 100000, 1970)
183        self.insert_overwrite('smith', 1, 'HR', 'janitor', 10000, 1970)
184        self.insert_overwrite('jones', 2, 'IT', 'sysadmin', 50000, 1980)
185        self.check_exists('smith', 1, 0)
186        self.check_exists('jones', 2, 0)
187        self.insert_duplicate('smith', 1, 'HR', 'manager', 100000, 1970)
188        result = ''
189        for i in xrange(self.NUM_INDICES):
190            result += '\n'.join(repr(cols)
191                for cols in self.index_iter(i))
192            result += '\n\n'
193        self.assertEqual(result, \
194            "['HR', 'HR', 'janitor', 10000, 1970]\n" + \
195            "['IT', 'IT', 'sysadmin', 50000, 1980]\n\n" + \
196            "['jones', 1980, 'IT', 'sysadmin', 50000, 1980]\n" + \
197            "['smith', 1970, 'HR', 'janitor', 10000, 1970]\n\n" + \
198            "[10000, 'HR', 'janitor', 10000, 1970]\n" + \
199            "[50000, 'IT', 'sysadmin', 50000, 1980]\n\n" + \
200            "['HR', 'janitor', 'smith', 'HR', 'janitor', 10000, 1970]\n" + \
201            "['IT', 'sysadmin', 'jones', 'IT', 'sysadmin', 50000, 1980]\n\n" + \
202            "['jones', 2, 'IT', 'sysadmin', 50000, 1980]\n" + \
203            "['smith', 1, 'HR', 'janitor', 10000, 1970]\n\n" + \
204            "[1, 'smith', 'HR', 'janitor', 10000, 1970]\n" + \
205            "[2, 'jones', 'IT', 'sysadmin', 50000, 1980]\n\n")
206
207        self.drop_table()
208
209    def test_insert_delete(self):
210        '''Create a table, add a key, remove it'''
211        self.create_table()
212        self.insert('smith', 1, 'HR', 'manager', 100000, 1970)
213        self.check_exists('smith', 1, 0)
214        self.remove('smith', 1)
215        self.check_exists('smith', 1, wiredtiger.WT_NOTFOUND)
216        for i in xrange(self.NUM_INDICES):
217            self.assertEqual(list(self.index_iter(i)), [])
218        self.drop_table()
219
220    def test_exclusive(self):
221        '''Create indices, then try to create another index exclusively'''
222        self.create_table()
223        # non-exclusive recreate is allowed
224        self.session.create(self.index[0], 'columns=(dept)')
225        # exclusive recreate
226        self.assertRaises(wiredtiger.WiredTigerError,
227            lambda: self.session.create(self.index[0],
228            'columns=(dept),exclusive'))
229        self.drop_table()
230
231if __name__ == '__main__':
232    wttest.run()
233