1 /* Copyright (c) 2000, 2011, 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 	/* Functions to handle fixed-length-records */
24 
25 #include "myisamdef.h"
26 
27 
_mi_write_static_record(MI_INFO * info,const uchar * record)28 int _mi_write_static_record(MI_INFO *info, const uchar *record)
29 {
30   uchar temp[8];				/* max pointer length */
31   if (info->s->state.dellink != HA_OFFSET_ERROR &&
32       !info->append_insert_at_end)
33   {
34     my_off_t filepos=info->s->state.dellink;
35     info->rec_cache.seek_not_done=1;		/* We have done a seek */
36     if (info->s->file_read(info, &temp[0],info->s->base.rec_reflength,
37 		info->s->state.dellink+1,
38 		 MYF(MY_NABP)))
39       goto err;
40     info->s->state.dellink= _mi_rec_pos(info->s,temp);
41     info->state->del--;
42     info->state->empty-=info->s->base.pack_reclength;
43     if (info->s->file_write(info, record, info->s->base.reclength,
44 		  filepos,
45 		  MYF(MY_NABP)))
46       goto err;
47   }
48   else
49   {
50     if (info->state->data_file_length > info->s->base.max_data_file_length-
51 	info->s->base.pack_reclength)
52     {
53       my_errno=HA_ERR_RECORD_FILE_FULL;
54       return(2);
55     }
56     if (info->opt_flag & WRITE_CACHE_USED)
57     {				/* Cash in use */
58       if (my_b_write(&info->rec_cache, record,
59 		     info->s->base.reclength))
60 	goto err;
61       if (info->s->base.pack_reclength != info->s->base.reclength)
62       {
63 	uint length=info->s->base.pack_reclength - info->s->base.reclength;
64 	memset(temp, 0, length);
65 	if (my_b_write(&info->rec_cache, temp,length))
66 	  goto err;
67       }
68     }
69     else
70     {
71       info->rec_cache.seek_not_done=1;		/* We have done a seek */
72       if (info->s->file_write(info, record, info->s->base.reclength,
73 		    info->state->data_file_length,
74 		    info->s->write_flag))
75         goto err;
76       if (info->s->base.pack_reclength != info->s->base.reclength)
77       {
78 	uint length=info->s->base.pack_reclength - info->s->base.reclength;
79 	memset(temp, 0, length);
80 	if (info->s->file_write(info, temp,length,
81 		      info->state->data_file_length+
82 		      info->s->base.reclength,
83 		      info->s->write_flag))
84     goto err;
85       }
86     }
87     info->state->data_file_length+=info->s->base.pack_reclength;
88     info->s->state.split++;
89   }
90   return 0;
91  err:
92   return 1;
93 }
94 
_mi_update_static_record(MI_INFO * info,my_off_t pos,const uchar * record)95 int _mi_update_static_record(MI_INFO *info, my_off_t pos, const uchar *record)
96 {
97   info->rec_cache.seek_not_done=1;		/* We have done a seek */
98   return (info->s->file_write(info,
99                               record, info->s->base.reclength,
100                               pos,
101                               MYF(MY_NABP)) != 0);
102 }
103 
104 
_mi_delete_static_record(MI_INFO * info)105 int _mi_delete_static_record(MI_INFO *info)
106 {
107   uchar temp[9];				/* 1+sizeof(uint32) */
108 
109   info->state->del++;
110   info->state->empty+=info->s->base.pack_reclength;
111   temp[0]= '\0';			/* Mark that record is deleted */
112   _mi_dpointer(info,temp+1,info->s->state.dellink);
113   info->s->state.dellink = info->lastpos;
114   info->rec_cache.seek_not_done=1;
115   return (info->s->file_write(info,(uchar*) temp, 1+info->s->rec_reflength,
116 		    info->lastpos, MYF(MY_NABP)) != 0);
117 }
118 
119 
_mi_cmp_static_record(MI_INFO * info,const uchar * old)120 int _mi_cmp_static_record(MI_INFO *info, const uchar *old)
121 {
122   DBUG_ENTER("_mi_cmp_static_record");
123 
124   if (info->opt_flag & WRITE_CACHE_USED)
125   {
126     if (flush_io_cache(&info->rec_cache))
127     {
128       DBUG_RETURN(-1);
129     }
130     info->rec_cache.seek_not_done=1;		/* We have done a seek */
131   }
132 
133   if ((info->opt_flag & READ_CHECK_USED))
134   {						/* If check isn't disabled  */
135     info->rec_cache.seek_not_done=1;		/* We have done a seek */
136     if (info->s->file_read(info, info->rec_buff, info->s->base.reclength,
137 		 info->lastpos,
138 		 MYF(MY_NABP)))
139       DBUG_RETURN(-1);
140     if (memcmp(info->rec_buff, old,
141 	       (uint) info->s->base.reclength))
142     {
143       DBUG_DUMP("read",old,info->s->base.reclength);
144       DBUG_DUMP("disk",info->rec_buff,info->s->base.reclength);
145       my_errno=HA_ERR_RECORD_CHANGED;		/* Record have changed */
146       DBUG_RETURN(1);
147     }
148   }
149   DBUG_RETURN(0);
150 }
151 
152 
_mi_cmp_static_unique(MI_INFO * info,MI_UNIQUEDEF * def,const uchar * record,my_off_t pos)153 int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def,
154 			  const uchar *record, my_off_t pos)
155 {
156   DBUG_ENTER("_mi_cmp_static_unique");
157 
158   info->rec_cache.seek_not_done=1;		/* We have done a seek */
159   if (info->s->file_read(info, info->rec_buff, info->s->base.reclength,
160 	       pos, MYF(MY_NABP)))
161     DBUG_RETURN(-1);
162   DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff,
163 			     def->null_are_equal));
164 }
165 
166 
167 	/* Read a fixed-length-record */
168 	/* Returns 0 if Ok. */
169 	/*	   1 if record is deleted */
170 	/*	  MY_FILE_ERROR on read-error or locking-error */
171 
_mi_read_static_record(MI_INFO * info,my_off_t pos,uchar * record)172 int _mi_read_static_record(MI_INFO *info, my_off_t pos,
173 			   uchar *record)
174 {
175   int error;
176 
177   if (pos != HA_OFFSET_ERROR)
178   {
179     if (info->opt_flag & WRITE_CACHE_USED &&
180 	info->rec_cache.pos_in_file <= pos &&
181 	flush_io_cache(&info->rec_cache))
182       return(-1);
183     info->rec_cache.seek_not_done=1;		/* We have done a seek */
184 
185     error=info->s->file_read(info, record, info->s->base.reclength,
186 		   pos,MYF(MY_NABP)) != 0;
187     fast_mi_writeinfo(info);
188     if (! error)
189     {
190       if (!*record)
191       {
192 	my_errno=HA_ERR_RECORD_DELETED;
193 	return(1);				/* Record is deleted */
194       }
195       info->update|= HA_STATE_AKTIV;		/* Record is read */
196       return(0);
197     }
198     return(-1);					/* Error on read */
199   }
200   fast_mi_writeinfo(info);			/* No such record */
201   return(-1);
202 }
203 
204 
205 
_mi_read_rnd_static_record(MI_INFO * info,uchar * buf,my_off_t filepos,my_bool skip_deleted_blocks)206 int _mi_read_rnd_static_record(MI_INFO *info, uchar *buf,
207 			       my_off_t filepos,
208 			       my_bool skip_deleted_blocks)
209 {
210   int locked,error,cache_read;
211   uint cache_length;
212   MYISAM_SHARE *share=info->s;
213   DBUG_ENTER("_mi_read_rnd_static_record");
214 
215   cache_read=0;
216   cache_length=0;
217   if (info->opt_flag & WRITE_CACHE_USED &&
218       (info->rec_cache.pos_in_file <= filepos || skip_deleted_blocks) &&
219       flush_io_cache(&info->rec_cache))
220     DBUG_RETURN(my_errno);
221   if (info->opt_flag & READ_CACHE_USED)
222   {						/* Cache in use */
223     if (filepos == my_b_tell(&info->rec_cache) &&
224 	(skip_deleted_blocks || !filepos))
225     {
226       cache_read=1;				/* Read record using cache */
227       cache_length=(uint) (info->rec_cache.read_end - info->rec_cache.read_pos);
228     }
229     else
230       info->rec_cache.seek_not_done=1;		/* Filepos is changed */
231   }
232   locked=0;
233   if (info->lock_type == F_UNLCK)
234   {
235     if (filepos >= info->state->data_file_length)
236     {						/* Test if new records */
237       if (_mi_readinfo(info,F_RDLCK,0))
238 	DBUG_RETURN(my_errno);
239       locked=1;
240     }
241     else
242     {						/* We don't nead new info */
243 #ifndef UNSAFE_LOCKING
244       if ((! cache_read || share->base.reclength > cache_length) &&
245 	  share->tot_locks == 0)
246       {						/* record not in cache */
247 	if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
248 		    MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
249 	  DBUG_RETURN(my_errno);
250 	locked=1;
251       }
252 #else
253       info->tmp_lock_type=F_RDLCK;
254 #endif
255     }
256   }
257   if (filepos >= info->state->data_file_length)
258   {
259     DBUG_PRINT("test",("filepos: %ld (%ld)  records: %ld  del: %ld",
260 		       (long) filepos/share->base.reclength, (long) filepos,
261 		       (long) info->state->records, (long) info->state->del));
262     fast_mi_writeinfo(info);
263     DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE);
264   }
265   info->lastpos= filepos;
266   info->nextpos= filepos+share->base.pack_reclength;
267 
268   if (! cache_read)			/* No cacheing */
269   {
270     if ((error=_mi_read_static_record(info,filepos,buf)))
271     {
272       if (error > 0)
273 	error=my_errno=HA_ERR_RECORD_DELETED;
274       else
275 	error=my_errno;
276     }
277     DBUG_RETURN(error);
278   }
279 
280   /*
281     Read record with caching. If my_b_read() returns TRUE, less than the
282     requested bytes have been read. In this case rec_cache.error is
283     either -1 for a read error, or contains the number of bytes copied
284     into the buffer.
285   */
286   error=my_b_read(&info->rec_cache,(uchar*) buf,share->base.reclength);
287   if (info->s->base.pack_reclength != info->s->base.reclength && !error)
288   {
289     char tmp[8];				/* Skill fill bytes */
290     error=my_b_read(&info->rec_cache,(uchar*) tmp,
291 		    info->s->base.pack_reclength - info->s->base.reclength);
292   }
293   if (locked)
294     (void) _mi_writeinfo(info,0);		/* Unlock keyfile */
295   if (!error)
296   {
297     if (!buf[0])
298     {						/* Record is removed */
299       DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
300     }
301 						/* Found and may be updated */
302     info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
303     DBUG_RETURN(0);
304   }
305   /* error is TRUE. my_errno should be set if rec_cache.error == -1 */
306   if (info->rec_cache.error != -1 || my_errno == 0)
307   {
308     /*
309       If we could not get a full record, we either have a broken record,
310       or are at end of file.
311     */
312     if (info->rec_cache.error == 0)
313       my_errno= HA_ERR_END_OF_FILE;
314     else
315       my_errno= HA_ERR_WRONG_IN_RECORD;
316   }
317   DBUG_RETURN(my_errno);			/* Something wrong (EOF?) */
318 }
319