1 /* Copyright (c) 2000, 2015, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
22
23 /* remove current record in heap-database */
24
25 #include "heapdef.h"
26
heap_delete(HP_INFO * info,const uchar * record)27 int heap_delete(HP_INFO *info, const uchar *record)
28 {
29 uchar *pos;
30 HP_SHARE *share=info->s;
31 HP_KEYDEF *keydef, *end, *p_lastinx;
32 DBUG_ENTER("heap_delete");
33 DBUG_PRINT("enter",("info: 0x%lx record: 0x%lx", (long) info, (long) record));
34
35 test_active(info);
36
37 if (info->opt_flag & READ_CHECK_USED && hp_rectest(info,record))
38 DBUG_RETURN(my_errno()); /* Record changed */
39 share->changed=1;
40
41 if ( --(share->records) < share->blength >> 1) share->blength>>=1;
42 pos=info->current_ptr;
43
44 p_lastinx = share->keydef + info->lastinx;
45 for (keydef = share->keydef, end = keydef + share->keys; keydef < end;
46 keydef++)
47 {
48 if ((*keydef->delete_key)(info, keydef, record, pos, keydef == p_lastinx))
49 goto err;
50 }
51
52 info->update=HA_STATE_DELETED;
53 *((uchar**) pos)=share->del_link;
54 share->del_link=pos;
55 pos[share->reclength]=0; /* Record deleted */
56 share->deleted++;
57 info->current_hash_ptr=0;
58 #if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
59 DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
60 #endif
61
62 DBUG_RETURN(0);
63 err:
64 if (++(share->records) == share->blength)
65 share->blength+= share->blength;
66 DBUG_RETURN(my_errno());
67 }
68
69
70 /*
71 Remove one key from rb-tree
72 */
73
hp_rb_delete_key(HP_INFO * info,HP_KEYDEF * keyinfo,const uchar * record,uchar * recpos,int flag)74 int hp_rb_delete_key(HP_INFO *info, HP_KEYDEF *keyinfo,
75 const uchar *record, uchar *recpos, int flag)
76 {
77 heap_rb_param custom_arg;
78 uint old_allocated;
79 int res;
80
81 if (flag)
82 info->last_pos= NULL; /* For heap_rnext/heap_rprev */
83
84 custom_arg.keyseg= keyinfo->seg;
85 custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
86 custom_arg.search_flag= SEARCH_SAME;
87 old_allocated= keyinfo->rb_tree.allocated;
88 res= tree_delete(&keyinfo->rb_tree, info->recbuf, custom_arg.key_length,
89 &custom_arg);
90 info->s->index_length-= (old_allocated - keyinfo->rb_tree.allocated);
91 return res;
92 }
93
94
95 /*
96 Remove one key from hash-table
97
98 SYNPOSIS
99 hp_delete_key()
100 info Hash handler
101 keyinfo key definition of key that we want to delete
102 record row data to be deleted
103 recpos Pointer to heap record in memory
104 flag Is set if we want's to correct info->current_ptr
105
106 RETURN
107 0 Ok
108 other Error code
109 */
110
hp_delete_key(HP_INFO * info,HP_KEYDEF * keyinfo,const uchar * record,uchar * recpos,int flag)111 int hp_delete_key(HP_INFO *info, HP_KEYDEF *keyinfo,
112 const uchar *record, uchar *recpos, int flag)
113 {
114 ulong blength, pos2, pos_hashnr, lastpos_hashnr, key_pos;
115 HASH_INFO *lastpos,*gpos,*pos,*pos3,*empty,*last_ptr;
116 HP_SHARE *share=info->s;
117 DBUG_ENTER("hp_delete_key");
118
119 blength=share->blength;
120 if (share->records+1 == blength)
121 blength+= blength;
122 lastpos=hp_find_hash(&keyinfo->block,share->records);
123 last_ptr=0;
124
125 /* Search after record with key */
126 key_pos= hp_mask(hp_rec_hashnr(keyinfo, record), blength, share->records + 1);
127 pos= hp_find_hash(&keyinfo->block, key_pos);
128
129 gpos = pos3 = 0;
130
131 while (pos->ptr_to_rec != recpos)
132 {
133 if (flag && !hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 0))
134 last_ptr=pos; /* Previous same key */
135 gpos=pos;
136 if (!(pos=pos->next_key))
137 {
138 set_my_errno(HA_ERR_CRASHED);
139 DBUG_RETURN(HA_ERR_CRASHED); /* This shouldn't happend */
140 }
141 }
142
143 /* Remove link to record */
144
145 if (flag)
146 {
147 /* Save for heap_rnext/heap_rprev */
148 info->current_hash_ptr=last_ptr;
149 info->current_ptr = last_ptr ? last_ptr->ptr_to_rec : 0;
150 DBUG_PRINT("info",("Corrected current_ptr to point at: 0x%lx",
151 (long) info->current_ptr));
152 }
153 empty=pos;
154 if (gpos)
155 gpos->next_key=pos->next_key; /* unlink current ptr */
156 else if (pos->next_key)
157 {
158 empty=pos->next_key;
159 *pos= *empty;
160 }
161 else
162 keyinfo->hash_buckets--;
163
164 if (empty == lastpos) /* deleted last hash key */
165 DBUG_RETURN (0);
166
167 /* Move the last key (lastpos) */
168 lastpos_hashnr= lastpos->hash;
169 /* pos is where lastpos should be */
170 pos=hp_find_hash(&keyinfo->block, hp_mask(lastpos_hashnr, share->blength,
171 share->records));
172 if (pos == empty) /* Move to empty position. */
173 {
174 empty[0]=lastpos[0];
175 DBUG_RETURN(0);
176 }
177 pos_hashnr= pos->hash;
178 /* pos3 is where the pos should be */
179 pos3= hp_find_hash(&keyinfo->block,
180 hp_mask(pos_hashnr, share->blength, share->records));
181 if (pos != pos3)
182 { /* pos is on wrong posit */
183 empty[0]=pos[0]; /* Save it here */
184 pos[0]=lastpos[0]; /* This shold be here */
185 hp_movelink(pos, pos3, empty); /* Fix link to pos */
186 DBUG_RETURN(0);
187 }
188 pos2= hp_mask(lastpos_hashnr, blength, share->records + 1);
189 if (pos2 == hp_mask(pos_hashnr, blength, share->records + 1))
190 { /* Identical key-positions */
191 if (pos2 != share->records)
192 {
193 empty[0]=lastpos[0];
194 hp_movelink(lastpos, pos, empty);
195 DBUG_RETURN(0);
196 }
197 pos3= pos; /* Link pos->next after lastpos */
198 /*
199 One of elements from the bucket we're scanning is moved to the
200 beginning of the list. Reset search since this element may not have
201 been processed yet.
202 */
203 if (flag && pos2 == key_pos)
204 {
205 info->current_ptr= 0;
206 info->current_hash_ptr= 0;
207 }
208 }
209 else
210 {
211 pos3= 0; /* Different positions merge */
212 keyinfo->hash_buckets--;
213 }
214
215 empty[0]=lastpos[0];
216 hp_movelink(pos3, empty, pos->next_key);
217 pos->next_key=empty;
218 DBUG_RETURN(0);
219 }
220