Commit a8ea31fa authored by unknown's avatar unknown

Add support for up to VARCHAR (size up to 65535)

Renamed HA_VAR_LENGTH to HA_VAR_LENGTH_PART
Renamed in all files FIELD_TYPE_STRING and FIELD_TYPE_VAR_STRING to MYSQL_TYPE_STRING and MYSQL_TYPE_VAR_STRING to make it easy to catch all possible errors
Added support for VARCHAR KEYS to heap
Removed support for ISAM
Now only long VARCHAR columns are changed to TEXT on demand (not CHAR)
Internal temporary files can now use fixed length tables if the used VARCHAR columns are short


BitKeeper/deleted/.del-ha_isam.cc~4dce65904db2675e:
  Delete: sql/ha_isam.cc
BitKeeper/deleted/.del-_cache.c~b5d80b5c3ae233b1:
  Delete: isam/_cache.c
BitKeeper/deleted/.del-_dbug.c~88d7964ae5e3c9bd:
  Delete: isam/_dbug.c
BitKeeper/deleted/.del-_dynrec.c~48dd758f5a5450df:
  Delete: isam/_dynrec.c
BitKeeper/deleted/.del-_key.c~ce62d47a6c681084:
  Delete: isam/_key.c
BitKeeper/deleted/.del-_locking.c~dea4cdc6ea425c67:
  Delete: isam/_locking.c
BitKeeper/deleted/.del-_packrec.c~47ae1b16c007e9be:
  Delete: isam/_packrec.c
BitKeeper/deleted/.del-_page.c~148b1a613d052ee8:
  Delete: isam/_page.c
BitKeeper/deleted/.del-_search.c~f509292aa1ff18ff:
  Delete: isam/_search.c
BitKeeper/deleted/.del-_statrec.c~58d9263b3475d58b:
  Delete: isam/_statrec.c
BitKeeper/deleted/.del-changed.c~d075de80a314b02d:
  Delete: isam/changed.c
BitKeeper/deleted/.del-close.c~fd62629496ee5bcc:
  Delete: isam/close.c
BitKeeper/deleted/.del-create.c~96cecc433c0c2242:
  Delete: isam/create.c
BitKeeper/deleted/.del-delete.c~65ee8daaa75a14b6:
  Delete: isam/delete.c
BitKeeper/deleted/.del-extra.c~706f29d72beb2565:
  Delete: isam/extra.c
BitKeeper/deleted/.del-info.c~96cfb747af8da0d:
  Delete: isam/info.c
BitKeeper/deleted/.del-isamchk.c~c0f59c2687d2248f:
  Delete: isam/isamchk.c
BitKeeper/deleted/.del-isamlog.c~85b6b31c6e2b8519:
  Delete: isam/isamlog.c
BitKeeper/deleted/.del-log.c~55a973013d55cade:
  Delete: isam/log.c
BitKeeper/deleted/.del-open.c~95b3b75042fae00a:
  Delete: isam/open.c
BitKeeper/deleted/.del-pack_isam.c~43801f0df7504834:
  Delete: isam/pack_isam.c
BitKeeper/deleted/.del-panic.c~f7fd71605324f8f3:
  Delete: isam/panic.c
BitKeeper/deleted/.del-range.c~142f1f8ac4948082:
  Delete: isam/range.c
BitKeeper/deleted/.del-rfirst.c~66f494291dc005d3:
  Delete: isam/rfirst.c
BitKeeper/deleted/.del-rkey.c~cc54c6498352f999:
  Delete: isam/rkey.c
BitKeeper/deleted/.del-rlast.c~d1fe1866139e9866:
  Delete: isam/rlast.c
BitKeeper/deleted/.del-rnext.c~b308eaa1e11ea7de:
  Delete: isam/rnext.c
BitKeeper/deleted/.del-rprev.c~b359f71fdea4bbce:
  Delete: isam/rprev.c
BitKeeper/deleted/.del-rrnd.c~7fcfcce88d4a5200:
  Delete: isam/rrnd.c
BitKeeper/deleted/.del-rsame.c~75a62d5548103a15:
  Delete: isam/rsame.c
BitKeeper/deleted/.del-rsamepos.c~5b5652dd2cda6d5d:
  Delete: isam/rsamepos.c
BitKeeper/deleted/.del-sort.c~e2e56b5a37ce86f4:
  Delete: isam/sort.c
BitKeeper/deleted/.del-static.c~3a1354b84f4a9cc7:
  Delete: isam/static.c
BitKeeper/deleted/.del-test1.c~64d52e9412d457ed:
  Delete: isam/test1.c
BitKeeper/deleted/.del-test2.c~2f9a632cab572958:
  Delete: isam/test2.c
BitKeeper/deleted/.del-test3.c~e8a7a4afe8a087:
  Delete: isam/test3.c
BitKeeper/deleted/.del-isamdef.h~ac8d49e7e2201c66:
  Delete: isam/isamdef.h
BitKeeper/deleted/.del-update.c~670264f51dc44934:
  Delete: isam/update.c
BitKeeper/deleted/.del-write.c~8f1918b1f6770e54:
  Delete: isam/write.c
BitKeeper/deleted/.del-Makefile.am~6cfa0db5e7778d09:
  Delete: isam/Makefile.am
BitKeeper/deleted/.del-make-ccc~3ee55391eda0b0ab:
  Delete: isam/make-ccc
BitKeeper/deleted/.del-ChangeLog~208984fb7a51e568:
  Delete: isam/ChangeLog
BitKeeper/deleted/.del-test_all.res~c2aafb49a3a77db7:
  Delete: isam/test_all.res
BitKeeper/deleted/.del-test_all~93c701e44a9c5b65:
  Delete: isam/test_all
BitKeeper/deleted/.del-.cvsignore~54f6f0f2d5012561:
  Delete: isam/.cvsignore
BitKeeper/deleted/.del-ha_isammrg.cc~dc682e4755d77a2e:
  Delete: sql/ha_isammrg.cc
BitKeeper/deleted/.del-ha_isam.h~bf53d533be3d3927:
  Delete: sql/ha_isam.h
BitKeeper/deleted/.del-ha_isammrg.h~66fd2e5bfe7207dc:
  Delete: sql/ha_isammrg.h
acinclude.m4:
  Remove ISAM
client/mysqldump.c:
  FIELD_TYPE -> MYSQL_TYPE
client/mysqltest.c:
  Add missing DBUG_RETURN
configure.in:
  Remove ISAM
heap/heapdef.h:
  Add support for VARCHAR
heap/hp_create.c:
  Add support for VARCHAR
heap/hp_delete.c:
  Add support for VARCHAR
heap/hp_hash.c:
  Add support for VARCHAR
  (VARCHAR keys was not supported before)
heap/hp_rkey.c:
  Add support for VARCHAR
heap/hp_update.c:
  Add support for VARCHAR
heap/hp_write.c:
  Add support for VARCHAR
  (Added flag SEARCH_UPDATE to mark that this is an update)
include/decimal.h:
  Remove not needed my_global.h
include/m_ctype.h:
  Add support for VARCHAR
include/my_base.h:
  Add support for VARCHAR
include/my_handler.h:
  Moved general purpose macro from MyISAM code
include/mysql_com.h:
  Add support for VARCHAR
libmysql/libmysql.c:
  Add support for VARCHAR
libmysqld/Makefile.am:
  Removed ISAM
myisam/ft_static.c:
  Add support for VARCHAR
myisam/ft_test1.c:
  Add support for VARCHAR
myisam/ft_update.c:
  Add support for VARCHAR
myisam/mi_check.c:
  Add support for VARCHAR
myisam/mi_create.c:
  Add support for VARCHAR
  - VARCHAR key segments are marked with HA_VAR_LENGTH_PART
myisam/mi_key.c:
  Add support for VARCHAR
  Fixed bug in old VARCHAR code when reading index-only
myisam/mi_range.c:
  Fixed comment style
myisam/mi_rnext_same.c:
  Handle case where equal keys can be of different length
myisam/mi_search.c:
  Add support for VARCHAR
myisam/mi_test1.c:
  Add support for VARCHAR
myisam/mi_unique.c:
  Add support for VARCHAR
  (Some new code to handle keys that are equal but have different lengths)
myisam/mi_write.c:
  Fixed comment
myisam/myisamchk.c:
  Better infotext if wrong type
mysql-test/r/bdb.result:
  Updated old result and new results for VARCHAR
mysql-test/r/create.result:
  Updated old result and new results for VARCHAR
mysql-test/r/ctype_tis620.result:
  Updated old result and new results for VARCHAR
  (Old code sorted tis620 wrong)
mysql-test/r/ctype_ucs.result:
  Updated old result and new results for VARCHAR
mysql-test/r/endspace.result:
  Updated old result and new results for VARCHAR
mysql-test/r/func_like.result:
  Updated old result and new results for VARCHAR
mysql-test/r/heap.result:
  Updated old result and new results for VARCHAR
mysql-test/r/innodb.result:
  Updated old result. This will change a bit when also InnoDB supports VARCHAR
mysql-test/r/merge.result:
  Updated old result and new results for VARCHAR
mysql-test/r/myisam.result:
  Updated old result and new results for VARCHAR
mysql-test/r/mysqldump.result:
  Updated old result and new results for VARCHAR
mysql-test/r/order_by.result:
  Updated old result and new results for VARCHAR
  (Key length is different for VARCHAR)
mysql-test/r/ps.result:
  Updated old result and new results for VARCHAR
mysql-test/r/ps_1general.result:
  Updated results for new .frm version
  Don't print seconds in show full process list as this may change
mysql-test/r/ps_2myisam.result:
  Updated old result and new results for VARCHAR
mysql-test/r/ps_3innodb.result:
  Updated old result and new results for VARCHAR
mysql-test/r/ps_4heap.result:
  Updated old result and new results for VARCHAR
mysql-test/r/ps_5merge.result:
  Updated old result and new results for VARCHAR
mysql-test/r/ps_6bdb.result:
  Updated old result and new results for VARCHAR
mysql-test/r/select.result.es:
  Updated results by hand
mysql-test/r/select.result:
  Updated old result and new results for VARCHAR
mysql-test/r/select_found.result:
  Updated old result and new results for VARCHAR
mysql-test/r/show_check.result:
  Updated old result and new results for VARCHAR
mysql-test/r/strict.result:
  Updated old result and new results for VARCHAR
mysql-test/r/subselect.result:
  Updated old result and new results for VARCHAR
mysql-test/r/system_mysql_db.result:
  Updated old result and new results for VARCHAR
mysql-test/r/type_blob.result:
  Updated old result and new results for VARCHAR
mysql-test/r/type_ranges.result:
  Updated old result and new results for VARCHAR
mysql-test/r/type_ranges.result.es:
  Updated some results by hand
mysql-test/t/bdb.test:
  Test VARCHAR
mysql-test/t/ctype_ucs.test:
  Some fixes related to VARCHAR
mysql-test/t/endspace.test:
  Fixes to make it easier to compare columns with end space
mysql-test/t/heap.test:
  Test VARCHAR
mysql-test/t/innodb.test:
  Prepare for testing VARCHAR
mysql-test/t/myisam.test:
  Test VARCHAR
mysql-test/t/ps_1general.test:
  Don't show seconds for show processlist
mysql-test/t/ps_4heap.test:
  Update for VARCHAR
mysql-test/t/strict.test:
  Fix test for VARCHAR
mysql-test/t/type_blob.test:
  Update test for VARCHAR
  Note that now you can't store 'a' and 'a ' in an unique varchar/text index if the column is not binary
mysys/my_handler.c:
  Add support for VARCHAR
ndb/src/common/util/NdbSqlUtil.cpp:
  Fix for usage of strnncollsp
scripts/mysql_fix_privilege_tables.sh:
  Simple fix so that my_print_defaults works
sql/Makefile.am:
  Remove ISAM
sql/field.cc:
  Add support for VARCHAR
  Fixed the keys for blob's are compared with strnncollsp
  Ensure that old tables from MySQL 4.0 works as they did before.
  (Old VARCHAR will be converted to new VARCHAR on ALTER TABLE)
sql/field.h:
  Add support for VARCHAR
sql/field_conv.cc:
  Change FIELD_TYPE_VAR_STRING -> MYSQL_TYPE_VARCHAR
  Added usage of HA_KEY_BLOB_LENGTH
sql/ha_berkeley.cc:
  Add support for VARCHAR
  Added usage of table->insert_or_update if we would ever want to know in key_cmp if we are changing keys
sql/ha_heap.cc:
  Add support for VARCHAR
sql/ha_innodb.cc:
  Changed MYSQL_TYPE_VAR_STRING to MYSQL_TYPE_VARCHAR.
  Waiting for Heikki to add full VARCHAR support
sql/ha_innodb.h:
  InnoDB doesn't support full VARCHAR yet
sql/ha_myisam.cc:
  Add support for VARCHAR
sql/ha_ndbcluster.cc:
  Add support for VARCHAR
sql/handler.h:
  Added HA_NO_VARCHAR for table handler that doesn't support VARCHAR. In this case MySQL will create a normal CHAR instead
sql/item.cc:
  Fixed access of already freed memory
  Added support of VARCHAR
  - varchar length is now checked in mysql_prepare
sql/item_cmpfunc.cc:
  Added new parameter to strncollsp
sql/item_sum.cc:
  Added new parameter to strncollsp
  FIELD_TYPE -> MYSQL_TYPE
sql/key.cc:
  Add support for VARCHAR
sql/opt_range.cc:
  Remove character set parameter from set_key_image()
sql/opt_sum.cc:
  Remove character set parameter from set_key_image()
sql/protocol.cc:
  Return MYSQL_TYPE_VAR_STRING instead of MYSQL_TYPE_VARCHAR to clients (to not cause compatiblity problems)
sql/sql_acl.cc:
  Change key handling code so that we can use CHAR or VARCHAR for the user table columns
sql/sql_base.cc:
  Remove old, not used code
sql/sql_help.cc:
  Remove charset from get_key_image
sql/sql_parse.cc:
  Ensure that OPTION_TABLE_LOCK is cleared ASAP; This fixed a problem in BDB transaction code when one used LOCK TABLES on a BDB table
  Added support for VARCHAR
  Moved field length checking and VARCHAR -> TEXT convert to mysql_prepare (as we need the know the character set for the column)
sql/sql_select.cc:
  Added support of VARCHAR
  Added heuristic to use fixed size rows for tmp tables if we are using only a few short VARCHAR's
sql/sql_string.cc:
  Added extra argument to strnncollsp
sql/sql_table.cc:
  Add support for VARCHAR
  Automaticly convert (with warning) big VARCHAR (but not CHAR) to TEXT
  If handler doesn't support VARCHAR convert VARCHAR to CHAR
sql/sql_update.cc:
  Fixed compiler warning
sql/sql_yacc.yy:
  Add support for VARCHAR
sql/strfunc.cc:
  Fixed valgrind warning
sql/structs.h:
  Added 'table' to KEY structure to make life easier for some handler functions
sql/table.cc:
  Add support for VARCHAR
  - New .frm version
  - FIELD_TYPE -> MYSQL_TYPE
sql/table.h:
  Added insert_or_update; A bool flag a handler can set/reset if needed (for handler internal usage)
sql/unireg.h:
  Add support for VARCHAR
strings/ctype-big5.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-bin.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
strings/ctype-czech.c:
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-gbk.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-latin1.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
strings/ctype-mb.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-simple.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-sjis.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-tis620.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-uca.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
strings/ctype-ucs2.c:
  Changed my_like_range... to correctly calculate min_length & max_length
strings/ctype-utf8.c:
  Added new argument to strnncollsp() to allow one to define if end space are significant or not
strings/ctype-win1250ch.c:
  Changed my_like_range... to correctly calculate min_length & max_length
strings/decimal.c:
  Fixed include files usage
  Fixed some compiler warnings
tests/client_test.c:
  Ensure tests works with VARCHAR
parent cd16e4c9
......@@ -1107,23 +1107,6 @@ AC_SUBST(orbit_libs)
AC_SUBST(orbit_idl)
])
AC_DEFUN([MYSQL_CHECK_ISAM], [
AC_ARG_WITH([isam], [
--with-isam Enable the ISAM table type],
[with_isam="$withval"],
[with_isam=no])
isam_libs=
if test X"$with_isam" = X"yes"
then
AC_DEFINE([HAVE_ISAM], [1], [Using old ISAM tables])
isam_libs="\$(top_builddir)/isam/libnisam.a\
\$(top_builddir)/merge/libmerge.a"
fi
AC_SUBST(isam_libs)
])
dnl ---------------------------------------------------------------------------
dnl Macro: MYSQL_CHECK_BDB
dnl Sets HAVE_BERKELEY_DB if inst library is found
......
......@@ -1546,12 +1546,13 @@ static void dumpTable(uint numFields, char *table)
we'll dump in hex only BLOB columns.
*/
is_blob= (opt_hex_blob && field->charsetnr == 63 &&
(field->type == FIELD_TYPE_STRING ||
field->type == FIELD_TYPE_VAR_STRING ||
field->type == FIELD_TYPE_BLOB ||
field->type == FIELD_TYPE_LONG_BLOB ||
field->type == FIELD_TYPE_MEDIUM_BLOB ||
field->type == FIELD_TYPE_TINY_BLOB)) ? 1 : 0;
(field->type == MYSQL_TYPE_STRING ||
field->type == MYSQL_TYPE_VAR_STRING ||
field->type == MYSQL_TYPE_VARCHAR ||
field->type == MYSQL_TYPE_BLOB ||
field->type == MYSQL_TYPE_LONG_BLOB ||
field->type == MYSQL_TYPE_MEDIUM_BLOB ||
field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
if (extended_insert)
{
ulong length = lengths[i];
......
......@@ -778,7 +778,7 @@ int var_set(const char *var_name, const char *var_name_end,
}
else
v = var_reg + digit;
return eval_expr(v, var_val, (const char**)&var_val_end);
DBUG_RETURN(eval_expr(v, var_val, (const char**)&var_val_end));
}
......
......@@ -2826,7 +2826,6 @@ AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_CHARSET_NAME], ["$default_charset"],
AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_COLLATION_NAME], ["$default_collation"],
[Define the default charset name])
MYSQL_CHECK_ISAM
MYSQL_CHECK_BDB
MYSQL_CHECK_INNODB
MYSQL_CHECK_EXAMPLEDB
......@@ -2889,12 +2888,6 @@ then
# Configuration for optional table handlers
#
if test X"$have_isam" != Xno
then
sql_server_dirs="$sql_server_dirs isam merge"
AC_CONFIG_FILES(isam/Makefile merge/Makefile)
fi
if test X"$have_berkeley_db" != Xno; then
if test X"$have_berkeley_db" != Xyes; then
# we must build berkeley db from source
......
......@@ -86,7 +86,8 @@ extern ulong hp_mask(ulong hashnr,ulong buffmax,ulong maxlength);
extern void hp_movelink(HASH_INFO *pos,HASH_INFO *next_link,
HASH_INFO *newlink);
extern int hp_rec_key_cmp(HP_KEYDEF *keydef,const byte *rec1,
const byte *rec2);
const byte *rec2,
my_bool diff_if_only_endspace_difference);
extern int hp_key_cmp(HP_KEYDEF *keydef,const byte *rec,
const byte *key);
extern void hp_make_key(HP_KEYDEF *keydef,byte *key,const byte *rec);
......@@ -94,6 +95,7 @@ extern uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
const byte *rec, byte *recpos);
extern uint hp_rb_key_length(HP_KEYDEF *keydef, const byte *key);
extern uint hp_rb_null_key_length(HP_KEYDEF *keydef, const byte *key);
extern uint hp_rb_var_key_length(HP_KEYDEF *keydef, const byte *key);
extern my_bool hp_if_null_in_key(HP_KEYDEF *keyinfo, const byte *record);
extern int hp_close(register HP_INFO *info);
extern void hp_clear(HP_SHARE *info);
......
......@@ -69,9 +69,21 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
case HA_KEYTYPE_UINT24:
case HA_KEYTYPE_INT8:
keyinfo->seg[j].flag|= HA_SWAP_KEY;
break;
case HA_KEYTYPE_VARBINARY:
/* Case-insensitiveness is handled in coll->hash_sort */
keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT;
/* fall_through */
case HA_KEYTYPE_VARTEXT:
if (!my_binary_compare(keyinfo->seg[j].charset))
keyinfo->flag|= HA_END_SPACE_KEY;
keyinfo->flag|= HA_VAR_LENGTH_KEY;
break;
default:
break;
}
if (keyinfo->seg[j].flag & HA_END_SPACE_ARE_EQUAL)
keyinfo->flag|= HA_END_SPACE_KEY;
}
keyinfo->length= length;
length+= keyinfo->rb_tree.size_of_element +
......@@ -82,7 +94,9 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
{
key_segs++; /* additional HA_KEYTYPE_END segment */
if (keyinfo->flag & HA_NULL_PART_KEY)
if (keyinfo->flag & HA_VAR_LENGTH_KEY)
keyinfo->get_key_length= hp_rb_var_key_length;
else if (keyinfo->flag & HA_NULL_PART_KEY)
keyinfo->get_key_length= hp_rb_null_key_length;
else
keyinfo->get_key_length= hp_rb_key_length;
......
......@@ -123,7 +123,7 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
while (pos->ptr_to_rec != recpos)
{
if (flag && !hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec))
if (flag && !hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 0))
last_ptr=pos; /* Previous same key */
gpos=pos;
if (!(pos=pos->next_key))
......
......@@ -246,14 +246,27 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
if (seg->type == HA_KEYTYPE_TEXT)
{
CHARSET_INFO *cs= seg->charset;
uint char_length= (uint) ((uchar*) key - pos);
uint length= seg->length;
if (cs->mbmaxlen > 1)
{
uint length= char_length;
uint char_length;
char_length= my_charpos(cs, pos, pos + length, length/cs->mbmaxlen);
set_if_smaller(char_length, length); /* QQ: ok to remove? */
set_if_smaller(length, char_length);
}
cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
}
else if (seg->type == HA_KEYTYPE_VARTEXT)
{
CHARSET_INFO *cs= seg->charset;
uint length= uint2korr(pos);
if (cs->mbmaxlen > 1)
{
uint char_length;
char_length= my_charpos(cs, pos +2, pos +2 + length,
seg->length/cs->mbmaxlen);
set_if_smaller(length, char_length);
}
cs->coll->hash_sort(cs, pos+2, length, &nr, &nr2);
}
else
{
......@@ -298,6 +311,19 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
}
cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
}
else if (seg->type == HA_KEYTYPE_VARTEXT)
{
CHARSET_INFO *cs= seg->charset;
uint length= uint2korr(pos);
if (cs->mbmaxlen > 1)
{
uint char_length;
char_length= my_charpos(cs, pos + 2 , pos + 2 + length,
seg->length/cs->mbmaxlen);
set_if_smaller(length, char_length);
}
cs->coll->hash_sort(cs, pos+2, length, &nr, &nr2);
}
else
{
for (; pos < end ; pos++)
......@@ -350,6 +376,11 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
{
seg->charset->hash_sort(seg->charset,pos,((uchar*)key)-pos,&nr,NULL);
}
else if (seg->type == HA_KEYTYPE_VARTEXT)
{
uint length= uint2korr(pos);
seg->charset->hash_sort(seg->charset, pos+2, length, &nr, NULL);
}
else
{
for ( ; pos < (uchar*) key ; pos++)
......@@ -384,6 +415,11 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
{
seg->charset->hash_sort(seg->charset,pos,((uchar*)key)-pos,&nr,NULL);
}
else if (seg->type == HA_KEYTYPE_VARTEXT)
{
uint length= uint2korr(pos);
seg->charset->hash_sort(seg->charset, pos+2, length, &nr, NULL);
}
else
{
for ( ; pos < end ; pos++)
......@@ -399,9 +435,28 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
#endif
/* Compare keys for two records. Returns 0 if they are identical */
/*
Compare keys for two records. Returns 0 if they are identical
int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
SYNOPSIS
hp_rec_key_cmp()
keydef Key definition
rec1 Record to compare
rec2 Other record to compare
diff_if_only_endspace_difference
Different number of end space is significant
NOTES
diff_if_only_endspace_difference is used to allow us to insert
'a' and 'a ' when there is an an unique key.
RETURN
0 Key is identical
<> 0 Key differes
*/
int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2,
my_bool diff_if_only_endspace_difference)
{
HA_KEYSEG *seg,*endseg;
......@@ -426,9 +481,9 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
{
uint char_length= seg->length / cs->mbmaxlen;
char_length1= my_charpos(cs, pos1, pos1 + seg->length, char_length);
set_if_smaller(char_length1, seg->length); /* QQ: ok to remove? */
set_if_smaller(char_length1, seg->length);
char_length2= my_charpos(cs, pos2, pos2 + seg->length, char_length);
set_if_smaller(char_length2, seg->length); /* QQ: ok to remove? */
set_if_smaller(char_length2, seg->length);
}
else
{
......@@ -436,7 +491,30 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
}
if (seg->charset->coll->strnncollsp(seg->charset,
pos1,char_length1,
pos2,char_length2))
pos2,char_length2, 0))
return 1;
}
else if (seg->type == HA_KEYTYPE_VARTEXT)
{
uchar *pos1= (uchar*)rec1 + seg->start;
uchar *pos2= (uchar*)rec2 + seg->start;
uint char_length1= uint2korr(pos1);
uint char_length2= uint2korr(pos2);
CHARSET_INFO *cs= seg->charset;
if (cs->mbmaxlen > 1)
{
uint char_length= seg->length / cs->mbmaxlen;
char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length);
set_if_smaller(char_length1, seg->length);
char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length);
set_if_smaller(char_length2, seg->length);
}
if (cs->coll->strnncollsp(seg->charset,
pos1+2, char_length1,
pos2+2, char_length2,
seg->flag & HA_END_SPACE_ARE_EQUAL ?
0 : diff_if_only_endspace_difference))
return 1;
}
else
......@@ -488,7 +566,31 @@ int hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key)
if (seg->charset->coll->strnncollsp(seg->charset,
(uchar*) pos, char_length_rec,
(uchar*) key, char_length_key))
(uchar*) key, char_length_key, 0))
return 1;
}
else if (seg->type == HA_KEYTYPE_VARTEXT)
{
uchar *pos= (uchar*) rec + seg->start;
CHARSET_INFO *cs= seg->charset;
uint char_length_rec= uint2korr(pos);
uint char_length_key= uint2korr(key);
if (cs->mbmaxlen > 1)
{
uint char_length= seg->length / cs->mbmaxlen;
char_length_key= my_charpos(cs, key+2, key +2 + char_length_key,
char_length);
set_if_smaller(char_length_key, seg->length);
char_length_rec= my_charpos(cs, pos +2 , pos + 2 + char_length_rec,
char_length);
set_if_smaller(char_length_rec, seg->length);
}
if (cs->coll->strnncollsp(seg->charset,
(uchar*) pos+2, char_length_rec,
(uchar*) key+2, char_length_key, 0))
return 1;
}
else
......@@ -525,6 +627,13 @@ void hp_make_key(HP_KEYDEF *keydef, byte *key, const byte *rec)
}
}
#define FIX_LENGTH(cs, pos, length, char_length) \
do { \
if (length > char_length) \
char_length= my_charpos(cs, pos, pos+length, char_length); \
set_if_smaller(char_length,length); \
} while(0)
uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
const byte *rec, byte *recpos)
......@@ -577,6 +686,24 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
}
continue;
}
if (seg->flag & HA_VAR_LENGTH_PART)
{
uchar *pos= (uchar*) rec + seg->start;
uint length= seg->length;
uint tmp_length= uint2korr(pos);
CHARSET_INFO *cs= seg->charset;
char_length= length/cs->mbmaxlen;
pos+=2; /* Skip VARCHAR length */
set_if_smaller(length,tmp_length);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
key+= char_length;
continue;
}
char_length= seg->length;
if (seg->charset->mbmaxlen > 1)
{
......@@ -627,6 +754,23 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
}
continue;
}
if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
{
/* Length of key-part used with heap_rkey() always 2 */
uint tmp_length=uint2korr(old);
uint length= seg->length;
CHARSET_INFO *cs= seg->charset;
char_length= length/cs->mbmaxlen;
k_len-= 2+length;
old+= 2;
set_if_smaller(length,tmp_length); /* Safety */
FIX_LENGTH(cs, old, length, char_length);
store_key_length_inc(key,char_length);
memcpy((byte*) key, old,(size_t) char_length);
key+= char_length;
continue;
}
char_length= seg->length;
if (seg->charset->mbmaxlen > 1)
{
......@@ -666,6 +810,27 @@ uint hp_rb_null_key_length(HP_KEYDEF *keydef, const byte *key)
return key - start_key;
}
uint hp_rb_var_key_length(HP_KEYDEF *keydef, const byte *key)
{
const byte *start_key= key;
HA_KEYSEG *seg, *endseg;
for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
{
uint length= seg->length;
if (seg->null_bit && !*key++)
continue;
if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
{
get_key_length(length, key);
}
key+= length;
}
return key - start_key;
}
/*
Test if any of the key parts are NULL.
Return:
......
......@@ -64,7 +64,7 @@ int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
info->update= 0;
DBUG_RETURN(my_errno);
}
if (!(keyinfo->flag & HA_NOSAME))
if (!(keyinfo->flag & HA_NOSAME) || (keyinfo->flag & HA_END_SPACE_KEY))
memcpy(info->lastkey, key, (size_t) keyinfo->length);
}
memcpy(record, pos, (size_t) share->reclength);
......
......@@ -37,7 +37,7 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new)
p_lastinx= share->keydef + info->lastinx;
for (keydef= share->keydef, end= keydef + share->keys; keydef < end; keydef++)
{
if (hp_rec_key_cmp(keydef, old, heap_new))
if (hp_rec_key_cmp(keydef, old, heap_new, 0))
{
if ((*keydef->delete_key)(info, keydef, old, pos, keydef == p_lastinx) ||
(*keydef->write_key)(info, keydef, heap_new, pos))
......@@ -74,7 +74,7 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new)
}
while (keydef >= share->keydef)
{
if (hp_rec_key_cmp(keydef, old, heap_new))
if (hp_rec_key_cmp(keydef, old, heap_new, 0))
{
if ((*keydef->delete_key)(info, keydef, heap_new, pos, 0) ||
(*keydef->write_key)(info, keydef, old, pos))
......
......@@ -106,7 +106,7 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *record,
custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
if (keyinfo->flag & HA_NOSAME)
{
custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME | SEARCH_UPDATE;
keyinfo->rb_tree.flag= TREE_NO_DUPS;
}
else
......@@ -293,7 +293,7 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
pos=empty;
do
{
if (! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec))
if (! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 1))
{
DBUG_RETURN(my_errno=HA_ERR_FOUND_DUPP_KEY);
}
......
......@@ -17,8 +17,6 @@
#ifndef _decimal_h
#define _decimal_h
#include <my_global.h>
typedef enum {TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} decimal_round_mode;
typedef int32 decimal_digit;
......
......@@ -106,7 +106,8 @@ typedef struct my_collation_handler_st
int (*strnncoll)(struct charset_info_st *,
const uchar *, uint, const uchar *, uint, my_bool);
int (*strnncollsp)(struct charset_info_st *,
const uchar *, uint, const uchar *, uint);
const uchar *, uint, const uchar *, uint,
my_bool diff_if_only_endspace_difference);
int (*strnxfrm)(struct charset_info_st *,
uchar *, uint, const uchar *, uint);
my_bool (*like_range)(struct charset_info_st *,
......@@ -259,7 +260,8 @@ extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, uint,
const uchar *, uint, my_bool);
extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, uint,
const uchar *, uint);
const uchar *, uint,
my_bool diff_if_only_endspace_difference);
extern void my_hash_sort_simple(CHARSET_INFO *cs,
const uchar *key, uint len,
......
......@@ -213,7 +213,7 @@ enum ha_base_keytype {
/*
Key has a part that can have end space. If this is an unique key
we have to handle it differently from other unique keys as we can find
many matching rows for one key (becaue end space are not compared)
many matching rows for one key (because end space are not compared)
*/
#define HA_END_SPACE_KEY 4096
......@@ -221,12 +221,17 @@ enum ha_base_keytype {
#define HA_SPACE_PACK 1 /* Pack space in key-seg */
#define HA_PART_KEY_SEG 4 /* Used by MySQL for part-key-cols */
#define HA_VAR_LENGTH 8
#define HA_VAR_LENGTH_PART 8
#define HA_NULL_PART 16
#define HA_BLOB_PART 32
#define HA_SWAP_KEY 64
#define HA_REVERSE_SORT 128 /* Sort key in reverse order */
#define HA_NO_SORT 256 /* do not bother sorting on this keyseg */
/*
End space in unique/varchar are considered equal. (Like 'a' and 'a ')
Only needed for internal temporary tables.
*/
#define HA_END_SPACE_ARE_EQUAL 512
/* optionbits for database */
#define HA_OPTION_PACK_RECORD 1
......@@ -345,6 +350,7 @@ enum ha_base_keytype {
#define HA_STATE_BUFF_SAVED 512 /* If current keybuff is info->buff */
#define HA_STATE_ROW_CHANGED 1024 /* To invalide ROW cache */
#define HA_STATE_EXTEND_BLOCK 2048
#define HA_STATE_RNEXT_SAME 4096 /* rnext_same was called */
enum en_fieldtype {
FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE,
......
......@@ -57,6 +57,13 @@ typedef struct st_HA_KEYSEG /* Key-portion */
{ length=mi_uint2korr((key)+1); (key)+=3; length_pack=3; } \
}
#define store_key_length_inc(key,length) \
{ if ((length) < 255) \
{ *(key)++=(length); } \
else \
{ *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \
}
extern int mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
my_bool, my_bool);
extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
......
......@@ -209,7 +209,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24,
MYSQL_TYPE_DATE, MYSQL_TYPE_TIME,
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE,
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
......
.deps
.libs
Makefile
Makefile.in
isamchk
isamlog
pack_isam
test1
test2
test3
2000-04-26 Michael Widenius <monty@mysql.com>
* Fixed bug when doing read_next after a delete/insert which balanced key
pages (In this case one internal buffer was wrongly reused)
1999-11-23 Michael Widenius <monty@monty.pp.sci.fi>
* Changed prefix from ni_ to nisam_ to avoid problems on MacOS X.
1999-08-17 Michael Widenius <monty@tik.pp.sci.fi>
* Changed last parameter to mi_open() to be a bit flag instead of an int.
1998-10-01 Michael Widenius <monty@monty.pp.sci.fi>
* Fixed bug in key packing when using some USE_STRCOLL character sets.
Thu Aug 20 23:17:41 1998 Michael Widenius <monty@bitch.pp.sci.fi>
* isamchk.c: Sometimes isamchk --sort-table caused isamchk to die.
1998-06-28 Michael Widenius <monty@monty.pp.sci.fi>
* Fixed some possible race conditions when using with MySQL and
many reopen/close of the same tables under heavy load!
* Changed isamchk to re-pack records when doing a repair to make it more safer.
Thu Mar 12 21:44:08 1998 Michael Widenius <monty@monty.pp.sci.fi>
* Added a safty test to _ni_rec_unpack.
Wed Nov 26 01:52:55 1997 <monty@monty.pp.sci.fi>
* Fixed small problem when reading delete-marked records with rkey, rnext and
rprev. In normal applications this should never happen.
Thu Nov 20 14:01:21 1997 <monty@monty.pp.sci.fi>
* Fixed range key bug when using compressed key where the first part wasn't
compressed.
* Converted everything to use prototypes.
Mon Sep 29 13:16:27 1997 <monty@monty.pp.sci.fi>
* Fixed problem with isamchk and compressed records files with record_reflength
< 4 (Gave wrong key when using isamchk -rq).
Fri Sep 26 16:06:37 1997 <monty@monty.pp.sci.fi>
* Fixed bug in range calculation.
Thu Aug 14 14:44:33 1997 <monty@monty.pp.sci.fi>
* Removed a couple of unnecessary seeks from 'delete static record'
Tue Jul 1 22:04:16 1997 <monty@monty.pp.sci.fi>
* Added checking of 'wrong packed records' when using 'isamchk -e' or
isamchk -ro.
Fri Feb 7 22:22:28 1997 Michael Widenius <monty@bitch.sci.fi>
* Fixed use of packed tables with threads (One static variable left)
Thu Jan 23 09:05:22 1997 Michael Widenius <monty@bitch.sci.fi>
* Changed create to detect keys > 127 and not pack them. Now one can
define keys with a length of up to (nisam_block_size-18)/2
by changeing N_MAX_KEY_LENGTH.
Fri Jan 10 21:01:44 1997 Michael Widenius <monty@bitch.sci.fi>
* added signed chars as key type.
Fri Apr 26 14:31:05 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
* create.c: All keyfile blocks are now IO_SIZE big (for better keycashing).
Tue Mar 12 22:42:52 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
* isamchk.c: Changed to print info if system table
* write.c: Don't allow more than 1 record in system table.
Fri Feb 2 16:40:32 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
* isamchk.c; Check that delete-link-chain is ok before trying to delete with 'q'.
Thu Jan 11 13:21:23 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
* All same isam files now shares a structure to allow many opens off the same
file
Sat Nov 25 12:33:53 1995 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
* All functions now used my_errno instead of errno
Mon Oct 23 12:32:02 1995 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
* isamchk.c: Don't print that database should be fixed on automatic rep.
Sun Aug 27 20:13:56 1995 Michael Widenius <monty@bitch.analytikerna.se (Michael Widenius)>
* _dynrec.c added flush_io_cash() if someone did a read when using
WRITE CASHING.
Thu Apr 20 01:41:24 1995 Michael Widenius (monty@bitch)
* fixed errno when got error of 'key-not-found' when updateing or
deleting record.
Tue Jan 17 19:37:48 1995 Michael Widenius (monty@bitch)
* isamchk can now unpack databases.
* prolinted all files.
Fri May 27 15:01:06 1994 Michael Widenius (monty@bitch)
* Don't lock packed databases.
Sat Apr 16 22:41:23 1994 Michael Widenius (monty@bitch)
* Added new function read_rsame_with_pos.
Wed Mar 30 15:52:19 1994 Michael Widenius (monty@bitch)
* Added creation and recover date to indexfile and isamchk.
Sat Mar 26 15:03:37 1994 Michael Widenius (monty@bitch)
* change is_panic() to close all files on ha_panic(write) on systems
(VMS) with can't open one file twice.
Fri Feb 4 21:09:56 1994 Michael Widenius (monty@bitch)
* READ_CASH on packed files now makes them mem-mapped if possibly
Sat Sep 18 14:56:32 1993 Michael Widenius (monty at bitch)
* changed _search to use pointer to buffer when reading keys.
Mon Aug 16 19:45:29 1993 Michael Widenius (monty at bitch)
* isamchk and packisam resolves symbolic links before file is used.
This forces temp-files on same disk as orginal file and rename
of temp-files dosen't destroy symbolic links.
Mon May 31 18:26:08 1993 Michael Widenius (monty at bitch)
* Added crc-check of records when packing for safe test if pack ok.
Tue Mar 2 19:16:00 1993 Michael Widenius (monty@bitch)
* Added logging of records with ni_log().
Fri Jan 29 00:56:58 1993 Michael Widenius (monty@bitch)
* Fixed bug in _read_rnd_static_record ; A lock was made for
each record even if it was in cash.
Sun Nov 15 12:51:36 1992 Michael Widenius (monty@bitch)
* last change breaked _dynrec, when not compileing with dbug.
Fri Nov 6 03:46:38 1992 Michael Widenius (monty@bitch)
* Fixed bugg when using packed records and reclength < 8 byte.
Wed Oct 28 22:23:32 1992 Michael Widenius (monty@bitch)
* Changed _cash.c to use io_cash to allow use of aioread.
Fri Oct 23 00:45:53 1992 Michael Widenius (monty@bitch)
* Added MY_WAIT_IF_FULL to pack_isam.
Sat Oct 17 14:51:15 1992 Michael Widenius (monty@bitch)
* Added use of subset of keys (isamchk -k#)
Mon Oct 5 21:53:18 1992 Michael Widenius (monty@bitch)
* Remove reloc of database ; Gives only problems with isamchk.
Mon Aug 17 03:17:09 1992 Michael Widenius (monty@bitch)
* Changed isam to use io_cash instead of rec_cash
# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
LDADD = @CLIENT_EXTRA_LDFLAGS@ libnisam.a ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
pkglib_LIBRARIES = libnisam.a
bin_PROGRAMS = isamchk isamlog pack_isam
isamchk_DEPENDENCIES= $(LIBRARIES)
isamlog_DEPENDENCIES= $(LIBRARIES)
pack_isam_DEPENDENCIES= $(LIBRARIES)
noinst_PROGRAMS = test1 test2 test3
noinst_HEADERS = isamdef.h
test1_DEPENDENCIES= $(LIBRARIES)
test2_DEPENDENCIES= $(LIBRARIES)
test3_DEPENDENCIES= $(LIBRARIES)
libnisam_a_SOURCES = open.c extra.c info.c rkey.c rnext.c \
_search.c _page.c _key.c _locking.c \
rrnd.c _cache.c _statrec.c _packrec.c \
_dynrec.c update.c write.c delete.c \
rprev.c rfirst.c rlast.c rsame.c rsamepos.c \
panic.c close.c create.c range.c _dbug.c \
log.c changed.c static.c
isamchk_SOURCES = isamchk.c sort.c
CLEANFILES = test?.IS? isam.log
# Move to automake rules ?
prolint:; plparse -b -u -hF1 "-width(0,0)" "-format=%f:%l:\s%t:%n\s%m" \
"-elib(????)" "+elib(?3??)" my.lnt $(nisam_SOURCES)
# Don't update the files from bitkeeper
%::SCCS/s.%
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Functions for read record cacheing with nisam */
/* Used instead of my_b_read() to allow for no-cacheed seeks */
#include "isamdef.h"
#define READING_NEXT 1
#define READING_HEADER 2
/* Copy block from cache if it`s in it. If re_read_if_possibly is */
/* set read to cache (if after current file-position) else read to */
/* buff */
int _nisam_read_cache(IO_CACHE *info, byte *buff, ulong pos, uint length,
int flag)
{
uint read_length,in_buff_length;
ulong offset;
char *in_buff_pos;
if (pos < info->pos_in_file)
{
read_length= (uint) min((ulong) length,(ulong) (info->pos_in_file-pos));
info->seek_not_done=1;
VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
if (my_read(info->file,buff,read_length,MYF(MY_NABP)))
return 1;
if (!(length-=read_length))
return 0;
pos+=read_length;
buff+=read_length;
}
if ((offset=pos - (ulong) info->pos_in_file) <
(ulong) (info->read_end - info->request_pos))
{
in_buff_pos=info->request_pos+(uint) offset;
in_buff_length= min(length,(uint) (info->read_end-in_buff_pos));
memcpy(buff,info->request_pos+(uint) offset,(size_t) in_buff_length);
if (!(length-=in_buff_length))
return 0;
pos+=in_buff_length;
buff+=in_buff_length;
}
else
in_buff_length=0;
if (flag & READING_NEXT)
{
if (pos != ((info)->pos_in_file +
(uint) ((info)->read_end - (info)->request_pos)))
{
info->pos_in_file=pos; /* Force start here */
info->read_pos=info->read_end=info->request_pos; /* Everything used */
info->seek_not_done=1;
}
else
info->read_pos=info->read_end; /* All block used */
if (!(*info->read_function)(info,buff,length))
return 0;
if (!(flag & READING_HEADER) || info->error == -1 ||
(uint) info->error+in_buff_length < 3)
return 1;
if (BLOCK_INFO_HEADER_LENGTH < in_buff_length + (uint) info->error)
bzero(buff+info->error,BLOCK_INFO_HEADER_LENGTH - in_buff_length -
(uint) info->error);
return 0;
}
info->seek_not_done=1;
VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
if ((read_length=my_read(info->file,buff,length,MYF(0))) == length)
return 0;
if (!(flag & READING_HEADER) || (int) read_length == -1 ||
read_length+in_buff_length < 3)
return 1;
bzero(buff+read_length,BLOCK_INFO_HEADER_LENGTH - in_buff_length -
read_length);
return 0;
} /* _nisam_read_cache */
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Support rutiner with are using with dbug */
#include "isamdef.h"
/* Print a key in user understandable format */
void _nisam_print_key(FILE *stream, register N_KEYSEG *keyseg, const uchar *key)
{
int flag;
short int s_1;
long int l_1;
float f_1;
double d_1;
uchar *end;
VOID(fputs("Key: \"",stream));
flag=0;
for (; keyseg->base.type ;keyseg++)
{
if (flag++)
VOID(putc('-',stream));
end= (uchar*) key+ keyseg->base.length;
switch (keyseg->base.type) {
case HA_KEYTYPE_BINARY:
if (!(keyseg->base.flag & HA_SPACE_PACK) && keyseg->base.length == 1)
{ /* packed binary digit */
VOID(fprintf(stream,"%d",(uint) *key++));
break;
}
/* fall through */
case HA_KEYTYPE_TEXT:
case HA_KEYTYPE_NUM:
if (keyseg->base.flag & HA_SPACE_PACK)
{
VOID(fprintf(stream,"%.*s",(int) *key,key+1));
key+= (int) *key+1;
}
else
{
VOID(fprintf(stream,"%.*s",(int) keyseg->base.length,key));
key=end;
}
break;
case HA_KEYTYPE_INT8:
VOID(fprintf(stream,"%d",(int) *((signed char*) key)));
key=end;
break;
case HA_KEYTYPE_SHORT_INT:
shortget(s_1,key);
VOID(fprintf(stream,"%d",(int) s_1));
key=end;
break;
case HA_KEYTYPE_USHORT_INT:
{
ushort u_1;
ushortget(u_1,key);
VOID(fprintf(stream,"%u",(uint) u_1));
key=end;
break;
}
case HA_KEYTYPE_LONG_INT:
longget(l_1,key);
VOID(fprintf(stream,"%ld",l_1));
key=end;
break;
case HA_KEYTYPE_ULONG_INT:
longget(l_1,key);
VOID(fprintf(stream,"%lu",(ulong) l_1));
key=end;
break;
case HA_KEYTYPE_INT24:
VOID(fprintf(stream,"%ld",(long) sint3korr(key)));
key=end;
break;
case HA_KEYTYPE_UINT24:
VOID(fprintf(stream,"%ld",(long) uint3korr(key)));
key=end;
break;
case HA_KEYTYPE_FLOAT:
bmove((byte*) &f_1,(byte*) key,(int) sizeof(float));
VOID(fprintf(stream,"%g",(double) f_1));
key=end;
break;
case HA_KEYTYPE_DOUBLE:
doubleget(d_1,key);
VOID(fprintf(stream,"%g",d_1));
key=end;
break;
#ifdef HAVE_LONG_LONG
case HA_KEYTYPE_LONGLONG:
{
char buff[21];
longlong tmp;
longlongget(tmp,key);
longlong2str(tmp,buff,-10);
VOID(fprintf(stream,"%s",buff));
key=end;
break;
}
case HA_KEYTYPE_ULONGLONG:
{
char buff[21];
longlong tmp;
longlongget(tmp,key);
longlong2str(tmp,buff,10);
VOID(fprintf(stream,"%s",buff));
key=end;
break;
}
#endif
default: break; /* This never happens */
}
}
VOID(fputs("\n",stream));
return;
} /* print_key */
This diff is collapsed.
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Functions to handle keys */
#include "isamdef.h"
#include "m_ctype.h"
static void _nisam_put_key_in_record(N_INFO *info,uint keynr,byte *record);
/* Make a intern key from a record */
/* If ascii key convert according to sortorder */
/* Ret: Length of key */
uint _nisam_make_key(register N_INFO *info, uint keynr, uchar *key, const char *record, ulong filepos)
{
uint length;
byte *pos,*end;
uchar *start;
reg1 N_KEYSEG *keyseg;
enum ha_base_keytype type;
DBUG_ENTER("_nisam_make_key");
start=key;
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->base.type ;keyseg++)
{
type=(enum ha_base_keytype) keyseg->base.type;
if (keyseg->base.flag & HA_SPACE_PACK)
{
pos= (byte*) record+keyseg->base.start; end=pos+keyseg->base.length;
if (type != HA_KEYTYPE_NUM)
{
while (end > pos && end[-1] == ' ')
end--;
}
else
{
while (pos < end && pos[0] == ' ')
pos++;
}
*key++= (uchar) (length=(uint) (end-pos));
memcpy((byte*) key,(byte*) pos,(size_t) length);
if (!use_strnxfrm(default_charset_info))
{
if (type == HA_KEYTYPE_TEXT)
my_strnxfrm(default_charset_info,(uchar*) key, length,
(uchar*) key, length);
}
key+=length;
}
else
{
memcpy((byte*) key,(byte*) record+keyseg->base.start,
(size_t) keyseg->base.length);
if (!use_strnxfrm(default_charset_info))
{
if (type == HA_KEYTYPE_TEXT)
my_strnxfrm(default_charset_info,(uchar*) key,
(uint) keyseg->base.length,
(uchar*) key,
(uint) keyseg->base.length);
}
#ifdef NAN_TEST
else if (type == HA_KEYTYPE_FLOAT)
{
float nr;
bmove((byte*) &nr,(byte*) key,sizeof(float));
if (nr == (float) FLT_MAX)
{
nr= (float) FLT_MAX;
bmove((byte*) key,(byte*) &nr,sizeof(float));
}
}
else if (type == HA_KEYTYPE_DOUBLE)
{
double nr;
bmove((byte*) &nr,(byte*) key,sizeof(double));
if (nr == DBL_MAX)
{
nr=DBL_MAX;
bmove((byte*) key,(byte*) &nr,sizeof(double));
}
}
#endif
key+= keyseg->base.length;
}
}
_nisam_dpointer(info,key,filepos);
DBUG_PRINT("exit",("keynr: %d",keynr));
DBUG_DUMP("key",(byte*) start,(uint) (key-start)+keyseg->base.length);
DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start););
DBUG_RETURN((uint) (key-start)); /* Return keylength */
} /* _nisam_make_key */
/* Pack a key to intern format from given format (c_rkey) */
/* if key_length is set returns new length of key */
uint _nisam_pack_key(register N_INFO *info, uint keynr, uchar *key, uchar *old, uint key_length)
/* Length of used key */
{
int k_length;
uint length;
uchar *pos,*end;
reg1 N_KEYSEG *keyseg;
enum ha_base_keytype type;
DBUG_ENTER("_nisam_pack_key");
if ((k_length=(int) key_length) <= 0)
k_length=N_MAX_KEY_BUFF;
for (keyseg=info->s->keyinfo[keynr].seg ;
keyseg->base.type && k_length >0;
k_length-=keyseg->base.length, old+=keyseg->base.length, keyseg++)
{
length=min((uint) keyseg->base.length,(uint) k_length);
type=(enum ha_base_keytype) keyseg->base.type;
if (keyseg->base.flag & HA_SPACE_PACK)
{
pos=old; end=pos+length;
if (type != HA_KEYTYPE_NUM)
{
while (end > pos && end[-1] == ' ')
end--;
}
else
{
while (pos < end && pos[0] == ' ')
pos++;
}
*key++ = (uchar) (length=(uint) (end-pos));
memcpy((byte*) key,pos,(size_t) length);
}
else
memcpy((byte*) key,old,(size_t) length);
if (!use_strnxfrm(default_charset_info))
{
if (type == HA_KEYTYPE_TEXT)
my_strnxfrm(default_charset_info,(uchar*) key,length,
(uchar*) key,length);
}
key+= length;
}
if (!keyseg->base.type)
{
if (k_length >= 0) /* Hole key */
key_length=0;
}
else
{ /* Part-key ; fill with null */
length= (uint) -k_length; /* unused part of last key */
do
{
length+= (keyseg->base.flag & HA_SPACE_PACK) ? 1 :
keyseg->base.length;
keyseg++;
} while (keyseg->base.type);
bzero((byte*) key,length);
}
DBUG_RETURN(key_length); /* Return part-keylength */
} /* _nisam_pack_key */
/* Put a key in record */
/* Used when only-keyread is wanted */
static void _nisam_put_key_in_record(register N_INFO *info, uint keynr, byte *record)
{
uint length;
reg2 byte *key;
byte *pos;
reg1 N_KEYSEG *keyseg;
DBUG_ENTER("_nisam_put_key_in_record");
key=(byte*) info->lastkey;
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->base.type ;keyseg++)
{
if (keyseg->base.flag & HA_SPACE_PACK)
{
length= (uint) (uchar) *key++;
pos= record+keyseg->base.start;
if (keyseg->base.type != (int) HA_KEYTYPE_NUM)
{
memcpy(pos,key,(size_t) length);
bfill(pos+length,keyseg->base.length-length,' ');
}
else
{
bfill(pos,keyseg->base.length-length,' ');
memcpy(pos+keyseg->base.length-length,key,(size_t) length);
}
key+=length;
}
else
{
memcpy(record+keyseg->base.start,(byte*) key,
(size_t) keyseg->base.length);
key+= keyseg->base.length;
}
}
DBUG_VOID_RETURN;
} /* _nisam_put_key_in_record */
/* Here when key reads are used */
int _nisam_read_key_record(N_INFO *info, ulong filepos, byte *buf)
{
VOID(_nisam_writeinfo(info,0));
if (filepos != NI_POS_ERROR)
{
if (info->lastinx >= 0)
{ /* Read only key */
_nisam_put_key_in_record(info,(uint) info->lastinx,buf);
info->update|= HA_STATE_AKTIV; /* We should find a record */
return 0;
}
my_errno=HA_ERR_WRONG_INDEX;
return(-1);
}
return(-1); /* Wrong data to read */
}
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
locking of isam-tables.
reads info from a isam-table. Must be first request before doing any furter
calls to any isamfunktion. Is used to allow many process use the same
isamdatabase.
*/
#include "isamdef.h"
#ifdef __WIN__
#include <errno.h>
#endif
/* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
int nisam_lock_database(N_INFO *info, int lock_type)
{
int error;
uint count;
ISAM_SHARE *share;
uint flag;
DBUG_ENTER("nisam_lock_database");
flag=error=0;
#ifndef NO_LOCKING
share=info->s;
if (share->base.options & HA_OPTION_READ_ONLY_DATA ||
info->lock_type == lock_type)
DBUG_RETURN(0);
pthread_mutex_lock(&share->intern_lock);
switch (lock_type) {
case F_UNLCK:
if (info->lock_type == F_RDLCK)
count= --share->r_locks;
else
count= --share->w_locks;
if (info->lock_type == F_WRLCK && !share->w_locks &&
flush_key_blocks(dflt_key_cache,share->kfile,FLUSH_KEEP))
error=my_errno;
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
if (end_io_cache(&info->rec_cache))
error=my_errno;
if (!count)
{
if (share->changed && !share->w_locks)
{
share->state.process= share->last_process=share->this_process;
share->state.loop= info->last_loop= ++info->this_loop;
share->state.uniq= info->last_uniq= info->this_uniq;
if (my_pwrite(share->kfile,(char*) &share->state.header,
share->state_length,0L,MYF(MY_NABP)))
error=my_errno;
share->changed=0;
#ifdef __WIN__
if (nisam_flush)
{
_commit(share->kfile);
_commit(info->dfile);
}
else
share->not_flushed=1;
#endif
}
if (share->r_locks)
{ /* Only read locks left */
flag=1;
if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
error=my_errno;
}
else if (!share->w_locks)
{ /* No more locks */
flag=1;
if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
error=my_errno;
}
}
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
info->lock_type= F_UNLCK;
break;
case F_RDLCK:
if (info->lock_type == F_WRLCK)
{ /* Change RW to READONLY */
if (share->w_locks == 1)
{
flag=1;
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
MYF(MY_SEEK_NOT_DONE)))
{
error=my_errno;
break;
}
}
share->w_locks--;
share->r_locks++;
info->lock_type=lock_type;
break;
}
if (!share->r_locks && !share->w_locks)
{
flag=1;
#ifdef HAVE_FCNTL
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
{
error=my_errno;
break;
}
if (my_pread(share->kfile,
(char*) &share->state.header,share->state_length,0L,
MYF(MY_NABP)))
{
error=my_errno;
VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
my_errno=error;
break;
}
#else
VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
{
error=my_errno;
break;
}
if (my_read(share->kfile,
(char*) &share->state.header,share->state_length,
MYF(MY_NABP)))
{
error=my_errno;
VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,info->lock_wait));
my_errno=error;
break;
}
#endif
}
VOID(_nisam_test_if_changed(info));
share->r_locks++;
info->lock_type=lock_type;
break;
case F_WRLCK:
if (info->lock_type == F_RDLCK)
{ /* Change RW to READONLY */
if (share->r_locks == 1)
{
flag=1;
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
MYF(info->lock_wait | MY_SEEK_NOT_DONE)))
{
error=my_errno;
break;
}
share->r_locks--;
share->w_locks++;
info->lock_type=lock_type;
break;
}
}
if (!(share->base.options & HA_OPTION_READ_ONLY_DATA) && !share->w_locks)
{
flag=1;
VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
{
error=my_errno;
break;
}
if (!share->r_locks)
{
if (my_read(share->kfile,
(char*) &share->state.header,share->state_length,
MYF(MY_NABP)))
{
error=my_errno;
VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,info->lock_wait));
my_errno=error;
break;
}
}
}
VOID(_nisam_test_if_changed(info));
info->lock_type=lock_type;
share->w_locks++;
break;
default:
break; /* Impossible */
}
pthread_mutex_unlock(&share->intern_lock);
#if defined(FULL_LOG) || defined(_lint)
lock_type|=(int) (flag << 8); /* Set bit to set if real lock */
nisam_log_command(LOG_LOCK,info,(byte*) &lock_type,sizeof(lock_type),
error);
#endif
#endif
DBUG_RETURN(error);
} /* nisam_lock_database */
/* Is used before access to database is granted */
int _nisam_readinfo(register N_INFO *info, int lock_type, int check_keybuffer)
{
ISAM_SHARE *share;
DBUG_ENTER("_nisam_readinfo");
share=info->s;
if (info->lock_type == F_UNLCK)
{
if (!share->r_locks && !share->w_locks)
{
#ifndef HAVE_FCNTL
VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
#endif
#ifndef NO_LOCKING
#ifdef UNSAFE_LOCKING
if ((info->tmp_lock_type=lock_type) != F_RDLCK)
#endif
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
DBUG_RETURN(1);
#endif
#ifdef HAVE_FCNTL
if (my_pread(share->kfile,
(char*) &share->state.header,share->state_length,0L,
MYF(MY_NABP)))
#else
if (my_read(share->kfile,
(char*) &share->state.header,share->state_length,
MYF(MY_NABP)))
#endif
{
#ifndef NO_LOCKING
int error=my_errno;
VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
MYF(MY_SEEK_NOT_DONE)));
my_errno=error;
#endif
DBUG_RETURN(1);
}
}
if (check_keybuffer)
VOID(_nisam_test_if_changed(info));
}
else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
{
my_errno=EACCES; /* Not allowed to change */
DBUG_RETURN(-1); /* when have read_lock() */
}
DBUG_RETURN(0);
} /* _nisam_readinfo */
/* Every isam-function that uppdates the isam-database must! end */
/* with this request */
/* ARGSUSED */
int _nisam_writeinfo(register N_INFO *info, uint flags)
{
int error,olderror;
ISAM_SHARE *share;
DBUG_ENTER("_nisam_writeinfo");
error=0;
share=info->s;
if (share->r_locks == 0 && share->w_locks == 0)
{
olderror=my_errno; /* Remember last error */
if (flags)
{ /* Two threads can't be here */
share->state.process= share->last_process= share->this_process;
share->state.loop= info->last_loop= ++info->this_loop;
share->state.uniq= info->last_uniq= info->this_uniq;
if ((error=my_pwrite(share->kfile,(char*) &share->state.header,
share->state_length,0L,MYF(MY_NABP)) != 0))
olderror=my_errno;
#ifdef __WIN__
if (nisam_flush)
{
_commit(share->kfile);
_commit(info->dfile);
}
#endif
}
if (flags != 2)
{
#ifndef NO_LOCKING
#ifdef UNSAFE_LOCKING
if (info->tmp_lock_type != F_RDLCK)
#endif
{
if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
DBUG_RETURN(1);
}
#endif
}
my_errno=olderror;
}
else if (flags)
share->changed= 1; /* Mark keyfile changed */
DBUG_RETURN(error);
} /* _nisam_writeinfo */
/* Test if someone has changed the database */
/* (Should be called after readinfo) */
int _nisam_test_if_changed(register N_INFO *info)
{
#ifndef NO_LOCKING
{
ISAM_SHARE *share=info->s;
if (share->state.process != share->last_process ||
share->state.loop != info->last_loop ||
share->state.uniq != info->last_uniq)
{ /* Keyfile has changed */
if (share->state.process != share->this_process)
VOID(flush_key_blocks(dflt_key_cache,share->kfile,FLUSH_RELEASE));
share->last_process=share->state.process;
info->last_loop= share->state.loop;
info->last_uniq= share->state.uniq;
info->update|= HA_STATE_WRITTEN; /* Must use file on next */
info->data_changed= 1; /* For nisam_is_changed */
return 1;
}
}
#endif
return (!(info->update & HA_STATE_AKTIV) ||
(info->update & (HA_STATE_WRITTEN | HA_STATE_DELETED |
HA_STATE_KEY_CHANGED)));
} /* _nisam_test_if_changed */
This diff is collapsed.
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* L{ser och skriver nyckelblock */
#include "isamdef.h"
#ifdef __WIN__
#include <errno.h>
#endif
/* Fetch a key-page in memory */
uchar *_nisam_fetch_keypage(register N_INFO *info, N_KEYDEF *keyinfo,
my_off_t page, uchar *buff, int return_buffer)
{
uchar *tmp;
tmp=(uchar*) key_cache_read(dflt_key_cache,
info->s->kfile,page,DFLT_INIT_HITS,(byte*) buff,
(uint) keyinfo->base.block_length,
(uint) keyinfo->base.block_length,
return_buffer);
if (tmp == info->buff)
{
info->update|=HA_STATE_BUFF_SAVED;
info->int_pos=(ulong) page;
info->buff_used=1;
}
else
{
info->update&= ~HA_STATE_BUFF_SAVED;
if (tmp)
info->int_pos=(ulong) page;
else
{
info->int_pos=NI_POS_ERROR;
DBUG_PRINT("error",("Got errno: %d from key_cache_read",my_errno));
my_errno=HA_ERR_CRASHED;
}
}
return tmp;
} /* _nisam_fetch_keypage */
/* Write a key-page on disk */
int _nisam_write_keypage(register N_INFO *info, register N_KEYDEF *keyinfo,
my_off_t page, uchar *buff)
{
reg3 uint length;
#ifndef QQ /* Safety check */
if (page < info->s->base.keystart ||
page+keyinfo->base.block_length > info->s->state.key_file_length ||
page & (nisam_block_size-1))
{
DBUG_PRINT("error",("Trying to write outside key region: %lu",
(long) page));
my_errno=EINVAL;
return(-1);
}
DBUG_PRINT("page",("write page at: %lu",(long) page,buff));
DBUG_DUMP("buff",(byte*) buff,getint(buff));
#endif
if ((length=keyinfo->base.block_length) > IO_SIZE*2 &&
info->s->state.key_file_length != page+length)
length= ((getint(buff)+IO_SIZE-1) & (uint) ~(IO_SIZE-1));
#ifdef HAVE_purify
{
length=getint(buff);
bzero((byte*) buff+length,keyinfo->base.block_length-length);
length=keyinfo->base.block_length;
}
#endif
return (key_cache_write(dflt_key_cache,
info->s->kfile,page,DFLT_INIT_HITS,
(byte*) buff,length,
(uint) keyinfo->base.block_length,
(int) (info->lock_type != F_UNLCK)));
} /* nisam_write_keypage */
/* Remove page from disk */
int _nisam_dispose(register N_INFO *info, N_KEYDEF *keyinfo, my_off_t pos)
{
uint keynr= (uint) (keyinfo - info->s->keyinfo);
ulong old_link; /* ulong is ok here */
DBUG_ENTER("_nisam_dispose");
old_link=info->s->state.key_del[keynr];
info->s->state.key_del[keynr]=(ulong) pos;
DBUG_RETURN(key_cache_write(dflt_key_cache,
info->s->kfile,pos,DFLT_INIT_HITS,
(byte*) &old_link,
sizeof(long),
(uint) keyinfo->base.block_length,
(int) (info->lock_type != F_UNLCK)));
} /* _nisam_dispose */
/* Make new page on disk */
ulong _nisam_new(register N_INFO *info, N_KEYDEF *keyinfo)
{
uint keynr= (uint) (keyinfo - info->s->keyinfo);
ulong pos;
DBUG_ENTER("_nisam_new");
if ((pos=info->s->state.key_del[keynr]) == NI_POS_ERROR)
{
if (info->s->state.key_file_length >= info->s->base.max_key_file_length)
{
my_errno=HA_ERR_INDEX_FILE_FULL;
DBUG_RETURN(NI_POS_ERROR);
}
pos=info->s->state.key_file_length;
info->s->state.key_file_length+= keyinfo->base.block_length;
}
else
{
if (!key_cache_read(dflt_key_cache,
info->s->kfile,pos,DFLT_INIT_HITS,
(byte*) &info->s->state.key_del[keynr],
(uint) sizeof(long),
(uint) keyinfo->base.block_length,0))
pos= NI_POS_ERROR;
}
DBUG_PRINT("exit",("Pos: %d",pos));
DBUG_RETURN(pos);
} /* _nisam_new */
This diff is collapsed.
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Functions to handle fixed-length-records */
#include "isamdef.h"
int _nisam_write_static_record(N_INFO *info, const byte *record)
{
uchar temp[4]; /* Not sizeof(long) */
if (info->s->state.dellink != NI_POS_ERROR)
{
ulong filepos=info->s->state.dellink;
info->rec_cache.seek_not_done=1; /* We have done a seek */
VOID(my_seek(info->dfile,info->s->state.dellink+1,MY_SEEK_SET,MYF(0)));
if (my_read(info->dfile,(char*) &temp[0],sizeof(temp), MYF(MY_NABP)))
goto err;
info->s->state.dellink=uint4korr(temp);
if (info->s->state.dellink == (uint32) ~0) /* Fix for 64 bit long */
info->s->state.dellink=NI_POS_ERROR;
info->s->state.del--;
info->s->state.empty-=info->s->base.reclength;
VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0)));
if (my_write(info->dfile, (char*) record, info->s->base.reclength,
MYF(MY_NABP)))
goto err;
}
else
{
if (info->s->state.data_file_length > info->s->base.max_data_file_length)
{
my_errno=HA_ERR_RECORD_FILE_FULL;
return(2);
}
if (info->opt_flag & WRITE_CACHE_USED)
{ /* Cash in use */
if (my_b_write(&info->rec_cache, (byte*) record, info->s->base.reclength))
goto err;
}
else
{
info->rec_cache.seek_not_done=1; /* We have done a seek */
VOID(my_seek(info->dfile,info->s->state.data_file_length,
MY_SEEK_SET,MYF(0)));
if (my_write(info->dfile,(char*) record,info->s->base.reclength,
MYF(MY_NABP | MY_WAIT_IF_FULL)))
goto err;
}
info->s->state.data_file_length+=info->s->base.reclength;
info->s->state.splitt++;
}
return 0;
err:
return 1;
}
int _nisam_update_static_record(N_INFO *info, ulong pos, const byte *record)
{
info->rec_cache.seek_not_done=1; /* We have done a seek */
VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0)));
return (my_write(info->dfile,(char*) record,info->s->base.reclength,
MYF(MY_NABP)) != 0);
}
int _nisam_delete_static_record(N_INFO *info)
{
uchar temp[5]; /* 1+sizeof(uint32) */
info->s->state.del++;
info->s->state.empty+=info->s->base.reclength;
temp[0]= '\0'; /* Mark that record is deleted */
int4store(temp+1,info->s->state.dellink);
info->s->state.dellink = info->lastpos;
info->rec_cache.seek_not_done=1;
VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
return (my_write(info->dfile,(byte*) temp,(uint) sizeof(temp),
MYF(MY_NABP)) != 0);
}
int _nisam_cmp_static_record(register N_INFO *info, register const byte *old)
{
DBUG_ENTER("_nisam_rectest");
/* We are going to do changes; dont let anybody disturb */
dont_break(); /* Dont allow SIGHUP or SIGINT */
if (info->opt_flag & WRITE_CACHE_USED)
{
if (flush_io_cache(&info->rec_cache))
{
DBUG_RETURN(-1);
}
info->rec_cache.seek_not_done=1; /* We have done a seek */
}
if ((info->opt_flag & READ_CHECK_USED))
{ /* If check isn't disabled */
info->rec_cache.seek_not_done=1; /* We have done a seek */
VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
MYF(MY_NABP)))
DBUG_RETURN(-1);
if (memcmp((byte*) info->rec_buff, (byte*) old,
(uint) info->s->base.reclength))
{
DBUG_DUMP("read",old,info->s->base.reclength);
DBUG_DUMP("disk",info->rec_buff,info->s->base.reclength);
my_errno=HA_ERR_RECORD_CHANGED; /* Record have changed */
DBUG_RETURN(1);
}
}
DBUG_RETURN(0);
}
/* Read a fixed-length-record */
/* Returns 0 if Ok. */
/* 1 if record is deleted */
/* MY_FILE_ERROR on read-error or locking-error */
int _nisam_read_static_record(register N_INFO *info, register ulong pos,
register byte *record)
{
int error;
if (pos != NI_POS_ERROR)
{
if (info->opt_flag & WRITE_CACHE_USED &&
info->rec_cache.pos_in_file <= pos &&
flush_io_cache(&info->rec_cache))
return(-1);
info->rec_cache.seek_not_done=1; /* We have done a seek */
error=my_pread(info->dfile,(char*) record,info->s->base.reclength,
pos,MYF(MY_NABP)) != 0;
if (info->s->r_locks == 0 && info->s->w_locks == 0)
VOID(_nisam_writeinfo(info,0));
if (! error)
{
if (!*record) return(1); /* Record is deleted */
info->update|= HA_STATE_AKTIV; /* Record is read */
my_errno=HA_ERR_RECORD_DELETED;
return(0);
}
return(-1); /* Error on read */
}
VOID(_nisam_writeinfo(info,0)); /* No such record */
return(-1);
} /* _nisam_read_record */
int _nisam_read_rnd_static_record(N_INFO *info, byte *buf,
register ulong filepos,
int skipp_deleted_blocks)
{
int locked,error,cache_read;
uint cache_length;
ISAM_SHARE *share=info->s;
DBUG_ENTER("_nisam_read_rnd_static_record");
cache_read=0;
LINT_INIT(cache_length);
if (info->opt_flag & WRITE_CACHE_USED &&
(info->rec_cache.pos_in_file <= filepos || skipp_deleted_blocks) &&
flush_io_cache(&info->rec_cache))
DBUG_RETURN(-1);
if (info->opt_flag & READ_CACHE_USED)
{ /* Cash in use */
if (filepos == my_b_tell(&info->rec_cache) &&
(skipp_deleted_blocks || !filepos))
{
cache_read=1; /* Read record using cache */
cache_length=(uint) (info->rec_cache.read_end - info->rec_cache.read_pos);
}
else
info->rec_cache.seek_not_done=1; /* Filepos is changed */
}
#ifndef NO_LOCKING
locked=0;
if (info->lock_type == F_UNLCK)
{
if (filepos >= share->state.data_file_length)
{ /* Test if new records */
if (_nisam_readinfo(info,F_RDLCK,0))
DBUG_RETURN(-1);
locked=1;
}
else
{ /* We don't nead new info */
#ifndef UNSAFE_LOCKING
if ((! cache_read || share->base.reclength > cache_length) &&
share->r_locks == 0 && share->w_locks == 0)
{ /* record not in cache */
if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
DBUG_RETURN(-1);
locked=1;
}
#else
info->tmp_lock_type=F_RDLCK;
#endif
}
}
#endif
if (filepos >= share->state.data_file_length)
{
#ifndef NO_LOCKING
DBUG_PRINT("test",("filepos: %ld (%ld) records: %ld del: %ld",
filepos/share->base.reclength,filepos,
share->state.records, share->state.del));
VOID(_nisam_writeinfo(info,0));
#endif
my_errno=HA_ERR_END_OF_FILE;
DBUG_RETURN(-1);
}
info->lastpos= filepos;
info->nextpos= filepos+share->base.reclength;
if (! cache_read) /* No cacheing */
{
error=_nisam_read_static_record(info,filepos,buf);
if (error > 0)
my_errno=HA_ERR_RECORD_DELETED;
DBUG_RETURN(error);
}
/* Read record with cacheing */
error=my_b_read(&info->rec_cache,(byte*) buf,share->base.reclength);
#ifndef NO_LOCKING
if (locked)
VOID(_nisam_writeinfo(info,0)); /* Unlock keyfile */
#endif
if (!error)
{
if (!buf[0])
{ /* Record is removed */
my_errno=HA_ERR_RECORD_DELETED;
DBUG_RETURN(1);
}
/* Found and may be updated */
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
DBUG_RETURN(0);
}
if (info->rec_cache.error != -1 || my_errno == 0)
my_errno=HA_ERR_WRONG_IN_RECORD;
DBUG_RETURN(-1); /* Something wrong (EOF?) */
}
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Check if somebody has changed table since last check. */
#include "isamdef.h"
/* Return 0 if table isn't changed */
int nisam_is_changed(N_INFO *info)
{
int result;
DBUG_ENTER("nisam_is_changed");
#ifndef NO_LOCKING
if (_nisam_readinfo(info,F_RDLCK,1)) DBUG_RETURN(-1);
VOID(_nisam_writeinfo(info,0));
#endif
result=(int) info->data_changed;
info->data_changed=0;
DBUG_PRINT("exit",("result: %d",result));
DBUG_RETURN(result);
}
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* close a isam-database */
#include "isamdef.h"
int nisam_close(register N_INFO *info)
{
int error=0,flag;
ISAM_SHARE *share=info->s;
DBUG_ENTER("nisam_close");
DBUG_PRINT("enter",("base: %lx reopen: %u locks: %u",
info,(uint) share->reopen,
(uint) (share->w_locks+share->r_locks)));
pthread_mutex_lock(&THR_LOCK_isam);
if (info->lock_type == F_EXTRA_LCK)
info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
#ifndef NO_LOCKING
if (info->lock_type != F_UNLCK)
VOID(nisam_lock_database(info,F_UNLCK));
#else
info->lock_type=F_UNLCK;
share->w_locks--;
if (_nisam_writeinfo(info,test(share->changed)))
error=my_errno;
#endif
pthread_mutex_lock(&share->intern_lock);
if (share->base.options & HA_OPTION_READ_ONLY_DATA)
share->r_locks--;
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
{
if (end_io_cache(&info->rec_cache))
error=my_errno;
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
}
flag= !--share->reopen;
nisam_open_list=list_delete(nisam_open_list,&info->open_list);
pthread_mutex_unlock(&share->intern_lock);
if (flag)
{
if (share->kfile >= 0 &&
flush_key_blocks(dflt_key_cache,share->kfile,FLUSH_RELEASE))
error=my_errno;
if (share->kfile >= 0 && my_close(share->kfile,MYF(0)))
error = my_errno;
#ifdef HAVE_MMAP
_nisam_unmap_file(info);
#endif
if (share->decode_trees)
{
my_free((gptr) share->decode_trees,MYF(0));
my_free((gptr) share->decode_tables,MYF(0));
}
#ifdef THREAD
thr_lock_delete(&share->lock);
VOID(pthread_mutex_destroy(&share->intern_lock));
#endif
my_free((gptr) info->s,MYF(0));
}
pthread_mutex_unlock(&THR_LOCK_isam);
if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
error = my_errno;
nisam_log_command(LOG_CLOSE,info,NULL,0,error);
my_free((gptr) info->rec_alloc,MYF(0));
my_free((gptr) info,MYF(0));
if (error)
{
my_errno=error;
DBUG_RETURN(-1);
}
DBUG_RETURN(0);
} /* nisam_close */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Ger tillbaka en struct med information om isam-filen */
#include "isamdef.h"
#ifdef __WIN__
#include <sys/stat.h>
#endif
ulong nisam_position(N_INFO *info)
{
return info->lastpos;
}
/* If flag == 1 one only gets pos of last record */
/* if flag == 2 one get current info (no sync from database */
int nisam_info(N_INFO *info, register N_ISAMINFO *x, int flag)
{
struct stat state;
ISAM_SHARE *share=info->s;
DBUG_ENTER("nisam_info");
x->recpos = info->lastpos;
if (flag & (HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE |
HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK))
{
#ifndef NO_LOCKING
if (!(flag & HA_STATUS_NO_LOCK))
{
pthread_mutex_lock(&share->intern_lock);
VOID(_nisam_readinfo(info,F_RDLCK,0));
VOID(_nisam_writeinfo(info,0));
pthread_mutex_unlock(&share->intern_lock);
}
#endif
x->records = share->state.records;
x->deleted = share->state.del;
x->delete_length= share->state.empty;
x->keys = share->state.keys;
x->reclength = share->base.reclength;
x->mean_reclength= share->state.records ?
(share->state.data_file_length-share->state.empty)/share->state.records :
share->min_pack_length;
x->data_file_length=share->state.data_file_length;
x->max_data_file_length=share->base.max_data_file_length;
x->index_file_length=share->state.key_file_length;
x->max_index_file_length=share->base.max_key_file_length;
x->filenr = info->dfile;
x->errkey = info->errkey;
x->dupp_key_pos= info->dupp_key_pos;
x->options = share->base.options;
x->create_time=share->base.create_time;
x->isamchk_time=share->base.isamchk_time;
x->rec_per_key=share->base.rec_per_key;
if ((flag & HA_STATUS_TIME) && !fstat(info->dfile,&state))
x->update_time=state.st_mtime;
else
x->update_time=0;
x->sortkey= -1; /* No clustering */
}
DBUG_RETURN(0);
} /* nisam_info */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
ccc -DHAVE_CONFIG_H -I. -I. -I.. -I./../include -I../include -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c _cache.c _dbug.c _dynrec.c _key.c _locking.c _packrec.c _page.c _search.c _statrec.c changed.c close.c create.c delete.c extra.c info.c log.c open.c panic.c range.c rfirst.c rkey.c rlast.c rnext.c rprev.c rrnd.c rsame.c rsamepos.c static.c update.c write.c
rm libnisam.a
ar -cr libnisam.a _cache.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* L{ser f|rsta posten som har samma isam-nyckel */
#include "isamdef.h"
/*
L{ser f|rsta posten med samma isamnyckel som f|reg}ende l{sning.
Man kan ha gjort write, update eller delete p} f|reg}ende post.
OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
*/
int nisam_rfirst(N_INFO *info, byte *buf, int inx)
{
DBUG_ENTER("nisam_rfirst");
info->lastpos= NI_POS_ERROR;
info->update|= HA_STATE_PREV_FOUND;
DBUG_RETURN(nisam_rnext(info,buf,inx));
} /* nisam_rfirst */
This diff is collapsed.
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* L{ser sista posten som har samma isam-nyckel */
#include "isamdef.h"
/*
L{ser sista posten med samma isamnyckel som f|reg}ende l{sning.
Man kan ha gjort write, update eller delete p} f|reg}ende post.
OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
*/
int nisam_rlast(N_INFO *info, byte *buf, int inx)
{
DBUG_ENTER("nisam_rlast");
info->lastpos= NI_POS_ERROR;
info->update|= HA_STATE_NEXT_FOUND;
DBUG_RETURN(nisam_rprev(info,buf,inx));
} /* nisam_rlast */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment