1 /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /* remove current record in heap-database */
24
25 #include <stddef.h>
26 #include <sys/types.h>
27
28 #include "my_dbug.h"
29 #include "my_inttypes.h"
30 #include "storage/heap/heapdef.h"
31
heap_delete(HP_INFO * info,const uchar * record)32 int heap_delete(HP_INFO *info, const uchar *record) {
33 uchar *pos;
34 HP_SHARE *share = info->s;
35 HP_KEYDEF *keydef, *end, *p_lastinx;
36 DBUG_TRACE;
37 DBUG_PRINT("enter", ("info: %p record: %p", info, record));
38
39 test_active(info);
40
41 if (info->opt_flag & READ_CHECK_USED && hp_rectest(info, record))
42 return my_errno(); /* Record changed */
43 share->changed = 1;
44
45 if (--(share->records) < share->blength >> 1) share->blength >>= 1;
46 pos = info->current_ptr;
47
48 p_lastinx = share->keydef + info->lastinx;
49 for (keydef = share->keydef, end = keydef + share->keys; keydef < end;
50 keydef++) {
51 if ((*keydef->delete_key)(info, keydef, record, pos, keydef == p_lastinx))
52 goto err;
53 }
54
55 info->update = HA_STATE_DELETED;
56 *((uchar **)pos) = share->del_link;
57 share->del_link = pos;
58 pos[share->reclength] = 0; /* Record deleted */
59 share->deleted++;
60 info->current_hash_ptr = nullptr;
61 #if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
62 DBUG_EXECUTE("check_heap", heap_check_heap(info, 0););
63 #endif
64
65 return 0;
66 err:
67 if (++(share->records) == share->blength) share->blength += share->blength;
68 return my_errno();
69 }
70
71 /*
72 Remove one key from rb-tree
73 */
74
hp_rb_delete_key(HP_INFO * info,HP_KEYDEF * keyinfo,const uchar * record,uchar * recpos,int flag)75 int hp_rb_delete_key(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *record,
76 uchar *recpos, int flag) {
77 heap_rb_param custom_arg;
78 uint old_allocated;
79 int res;
80
81 if (flag) info->last_pos = nullptr; /* For heap_rnext/heap_rprev */
82
83 custom_arg.keyseg = keyinfo->seg;
84 custom_arg.key_length = hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
85 custom_arg.search_flag = SEARCH_SAME;
86 old_allocated = keyinfo->rb_tree.allocated;
87 res = tree_delete(&keyinfo->rb_tree, info->recbuf, custom_arg.key_length,
88 &custom_arg);
89 info->s->index_length -= (old_allocated - keyinfo->rb_tree.allocated);
90 return res;
91 }
92
93 /*
94 Remove one key from hash-table
95
96 SYNPOSIS
97 hp_delete_key()
98 info Hash handler
99 keyinfo key definition of key that we want to delete
100 record row data to be deleted
101 recpos Pointer to heap record in memory
102 flag Is set if we want's to correct info->current_ptr
103
104 RETURN
105 0 Ok
106 other Error code
107 */
108
hp_delete_key(HP_INFO * info,HP_KEYDEF * keyinfo,const uchar * record,uchar * recpos,int flag)109 int hp_delete_key(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *record,
110 uchar *recpos, int flag) {
111 ulong blength, pos2, pos_hashnr, lastpos_hashnr, key_pos;
112 HASH_INFO *lastpos, *gpos, *pos, *pos3, *empty, *last_ptr;
113 HP_SHARE *share = info->s;
114 DBUG_TRACE;
115
116 blength = share->blength;
117 if (share->records + 1 == blength) blength += blength;
118 lastpos = hp_find_hash(&keyinfo->block, share->records);
119 last_ptr = nullptr;
120
121 /* Search after record with key */
122 key_pos =
123 hp_mask(hp_rec_hashnr(keyinfo, record), blength, share->records + 1);
124 pos = hp_find_hash(&keyinfo->block, key_pos);
125
126 gpos = pos3 = nullptr;
127
128 while (pos->ptr_to_rec != recpos) {
129 if (flag && !hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec))
130 last_ptr = pos; /* Previous same key */
131 gpos = pos;
132 if (!(pos = pos->next_key)) {
133 set_my_errno(HA_ERR_CRASHED);
134 return HA_ERR_CRASHED; /* This shouldn't happend */
135 }
136 }
137
138 /* Remove link to record */
139
140 if (flag) {
141 /* Save for heap_rnext/heap_rprev */
142 info->current_hash_ptr = last_ptr;
143 info->current_ptr = last_ptr ? last_ptr->ptr_to_rec : nullptr;
144 DBUG_PRINT("info",
145 ("Corrected current_ptr to point at: %p", info->current_ptr));
146 }
147 empty = pos;
148 if (gpos)
149 gpos->next_key = pos->next_key; /* unlink current ptr */
150 else if (pos->next_key) {
151 empty = pos->next_key;
152 *pos = *empty;
153 } else
154 keyinfo->hash_buckets--;
155
156 if (empty == lastpos) /* deleted last hash key */
157 return 0;
158
159 /* Move the last key (lastpos) */
160 lastpos_hashnr = lastpos->hash;
161 /* pos is where lastpos should be */
162 pos = hp_find_hash(&keyinfo->block,
163 hp_mask(lastpos_hashnr, share->blength, share->records));
164 if (pos == empty) /* Move to empty position. */
165 {
166 empty[0] = lastpos[0];
167 return 0;
168 }
169 pos_hashnr = pos->hash;
170 /* pos3 is where the pos should be */
171 pos3 = hp_find_hash(&keyinfo->block,
172 hp_mask(pos_hashnr, share->blength, share->records));
173 if (pos != pos3) { /* pos is on wrong posit */
174 empty[0] = pos[0]; /* Save it here */
175 pos[0] = lastpos[0]; /* This shold be here */
176 hp_movelink(pos, pos3, empty); /* Fix link to pos */
177 return 0;
178 }
179 pos2 = hp_mask(lastpos_hashnr, blength, share->records + 1);
180 if (pos2 == hp_mask(pos_hashnr, blength,
181 share->records + 1)) { /* Identical key-positions */
182 if (pos2 != share->records) {
183 empty[0] = lastpos[0];
184 hp_movelink(lastpos, pos, empty);
185 return 0;
186 }
187 pos3 = pos; /* Link pos->next after lastpos */
188 /*
189 One of elements from the bucket we're scanning is moved to the
190 beginning of the list. Reset search since this element may not have
191 been processed yet.
192 */
193 if (flag && pos2 == key_pos) {
194 info->current_ptr = nullptr;
195 info->current_hash_ptr = nullptr;
196 }
197 } else {
198 pos3 = nullptr; /* Different positions merge */
199 keyinfo->hash_buckets--;
200 }
201
202 empty[0] = lastpos[0];
203 hp_movelink(pos3, empty, pos->next_key);
204 pos->next_key = empty;
205 return 0;
206 }
207