summaryrefslogtreecommitdiff
path: root/sql/key.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/key.cc')
-rw-r--r--sql/key.cc266
1 files changed, 266 insertions, 0 deletions
diff --git a/sql/key.cc b/sql/key.cc
new file mode 100644
index 00000000000..df3f0fe25d5
--- /dev/null
+++ b/sql/key.cc
@@ -0,0 +1,266 @@
+/* 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 and fields in forms */
+
+#include "mysql_priv.h"
+
+ /*
+ ** Search after with key field is. If no key starts with field test
+ ** if field is part of some key.
+ **
+ ** returns number of key. keylength is set to length of key before
+ ** (not including) field
+ ** Used when calculating key for NEXT_NUMBER
+ */
+
+int find_ref_key(TABLE *table,Field *field, uint *key_length)
+{
+ reg2 int i;
+ reg3 KEY *key_info;
+ uint fieldpos;
+
+ fieldpos= field->offset();
+
+ /* Test if some key starts as fieldpos */
+
+ for (i=0, key_info=table->key_info ; i < (int) table->keys ; i++, key_info++)
+ {
+ if (key_info->key_part[0].offset == fieldpos)
+ { /* Found key. Calc keylength */
+ *key_length=0;
+ return(i); /* Use this key */
+ }
+ }
+ /* Test if some key contains fieldpos */
+
+ for (i=0, key_info=table->key_info ; i < (int) table->keys ; i++, key_info++)
+ {
+ uint j;
+ KEY_PART_INFO *key_part;
+ *key_length=0;
+ for (j=0, key_part=key_info->key_part ;
+ j < key_info->key_parts ;
+ j++, key_part++)
+ {
+ if (key_part->offset == fieldpos)
+ return(i); /* Use this key */
+ *key_length+=key_part->length;
+ }
+ }
+ return(-1); /* No key is ok */
+}
+
+
+ /* Copy a key from record to some buffer */
+ /* if length == 0 then copy hole key */
+
+void key_copy(byte *key,TABLE *table,uint idx,uint key_length)
+{
+ uint length;
+ KEY *key_info=table->key_info+idx;
+ KEY_PART_INFO *key_part;
+
+ if (key_length == 0)
+ key_length=key_info->key_length+key_info->extra_length;
+ for (key_part=key_info->key_part;
+ (int) key_length > 0 ;
+ key_part++)
+ {
+ if (key_part->null_bit)
+ {
+ *key++= test(table->record[0][key_part->null_offset] &
+ key_part->null_bit);
+ key_length--;
+ }
+ if (key_part->key_part_flag & HA_BLOB_PART)
+ {
+ char *pos;
+ ulong blob_length=((Field_blob*) key_part->field)->get_length();
+ key_length-=2;
+ ((Field_blob*) key_part->field)->get_ptr(&pos);
+ length=min(key_length,key_part->length);
+ set_if_smaller(blob_length,length);
+ int2store(key,(uint) blob_length);
+ key+=2; // Skipp length info
+ memcpy(key,pos,blob_length);
+ }
+ else
+ {
+ length=min(key_length,key_part->length);
+ memcpy(key,table->record[0]+key_part->offset,(size_t) length);
+ }
+ key+=length;
+ key_length-=length;
+ }
+} /* key_copy */
+
+
+ /* restore a key from some buffer to record */
+
+void key_restore(TABLE *table,byte *key,uint idx,uint key_length)
+{
+ uint length;
+ KEY *key_info=table->key_info+idx;
+ KEY_PART_INFO *key_part;
+
+ if (key_length == 0)
+ {
+ if (idx == (uint) -1)
+ return;
+ key_length=key_info->key_length+key_info->extra_length;
+ }
+ for (key_part=key_info->key_part;
+ (int) key_length > 0 ;
+ key_part++)
+ {
+ if (key_part->null_bit)
+ {
+ if (*key++)
+ table->record[0][key_part->null_offset]|= key_part->null_bit;
+ else
+ table->record[0][key_part->null_offset]&= ~key_part->null_bit;
+ key_length--;
+ }
+ if (key_part->key_part_flag & HA_BLOB_PART)
+ {
+ uint blob_length=uint2korr(key);
+ key+=2;
+ key_length-=2;
+ ((Field_blob*) key_part->field)->set_ptr((ulong) blob_length,
+ (char*) key);
+ length=key_part->length;
+ }
+ else
+ {
+ length=min(key_length,key_part->length);
+ memcpy(table->record[0]+key_part->offset,key,(size_t) length);
+ }
+ key+=length;
+ key_length-=length;
+ }
+} /* key_restore */
+
+
+ /* Compare if a key has changed */
+
+int key_cmp(TABLE *table,const byte *key,uint idx,uint key_length)
+{
+ uint length;
+ KEY_PART_INFO *key_part;
+
+ for (key_part=table->key_info[idx].key_part;
+ (int) key_length > 0;
+ key_part++, key+=length, key_length-=length)
+ {
+ if (key_part->null_bit)
+ {
+ key_length--;
+ if (*key != test(table->record[0][key_part->null_offset] &
+ key_part->null_bit))
+ return 1;
+ if (*key)
+ {
+ length=key_part->store_length;
+ continue;
+ }
+ key++;
+ }
+ if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ {
+ if (key_part->field->key_cmp(key, key_part->length+2))
+ return 1;
+ length=key_part->length+2;
+ }
+ else
+ {
+ length=min(key_length,key_part->length);
+ if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
+ FIELDFLAG_PACK)))
+ {
+ if (my_sortcmp((char*) key,(char*) table->record[0]+key_part->offset,
+ length))
+ return 1;
+ }
+ else if (memcmp(key,table->record[0]+key_part->offset,length))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+ /* unpack key-fields from record to some buffer */
+ /* This is used to get a good error message */
+
+void key_unpack(String *to,TABLE *table,uint idx)
+{
+ KEY_PART_INFO *key_part,*key_part_end;
+ Field *field;
+ String tmp;
+ DBUG_ENTER("key_unpack");
+
+ to->length(0);
+ for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
+ table->key_info[idx].key_parts ;
+ key_part < key_part_end;
+ key_part++)
+ {
+ if (to->length())
+ to->append('-');
+ if (key_part->null_bit)
+ {
+ if (table->record[0][key_part->null_offset] & key_part->null_bit)
+ {
+ to->append("NULL");
+ continue;
+ }
+ }
+ if ((field=key_part->field))
+ {
+ field->val_str(&tmp,&tmp);
+ if (key_part->length < field->pack_length())
+ tmp.length(min(tmp.length(),key_part->length));
+ to->append(tmp);
+ }
+ else
+ to->append("???");
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/* Return 1 if any field in a list is part of key */
+
+bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
+{
+ List_iterator<Item> f(fields);
+ KEY_PART_INFO *key_part,*key_part_end;
+ for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
+ table->key_info[idx].key_parts ;
+ key_part < key_part_end;
+ key_part++)
+ {
+ Item_field *field;
+ f.rewind();
+ while ((field=(Item_field*) f++))
+ {
+ if (key_part->field == field->field)
+ return 1;
+ }
+ }
+ return 0;
+}