~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL AB
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 as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/**
17
  @file
18
19
  @details
20
@verbatim
21
The idea of presented algorithm see in 
22
"The Art of Computer Programming" by Donald E. Knuth
23
Volume 3 "Sorting and searching"
24
(chapter 6.3 "Digital searching" - name and number of chapter 
25
   is back translation from Russian edition :))
26
27
as illustration of data structures, imagine next table:
28
29
static SYMBOL symbols[] = {
30
  { "ADD",              SYM(ADD),0,0},
31
  { "AND",              SYM(AND),0,0},
32
  { "DAY",              SYM(DAY_SYM),0,0},
33
};
34
35
for this structure, presented program generate next searching-structure:
36
37
+-----------+-+-+-+
38
|       len |1|2|3|
39
+-----------+-+-+-+
40
|first_char |0|0|a|
41
|last_char  |0|0|d|
42
|link       |0|0|+|
43
                 |
44
                 V
45
       +----------+-+-+-+--+
46
       |    1 char|a|b|c|d |
47
       +----------+-+-+-+--+
48
       |first_char|b|0|0|0 |
49
       |last_char |n|0|0|-1|
50
       |link      |+|0|0|+ |
51
                   |     |
52
                   |     V
53
                   |  symbols[2] ( "DAY" )
54
                   V
55
+----------+--+-+-+-+-+-+-+-+-+-+--+
56
|    2 char|d |e|f|j|h|i|j|k|l|m|n |
57
+----------+--+-+-+-+-+-+-+-+-+-+--+
58
|first_char|0 |0|0|0|0|0|0|0|0|0|0 |
59
|last_char |-1|0|0|0|0|0|0|0|0|0|-1|
60
|link      |+ |0|0|0|0|0|0|0|0|0|+ |
61
            |                    |
62
            V                    V
63
         symbols[0] ( "ADD" )  symbols[1] ( "AND" )
64
65
for optimization, link is the 16-bit index in 'symbols' or 'sql_functions'
66
or search-array..
67
68
So, we can read full search-structure as 32-bit word
69
@endverbatim
70
71
@todo
72
    use instead to_upper_lex, special array 
73
    (substitute chars) without skip codes..
74
@todo
75
    try use reverse order of comparing..
76
77
*/
78
79
#define NO_YACC_SYMBOLS
80
#include "my_global.h"
212.5.13 by Monty Taylor
Moved my_sys/my_pthread/my_nosys and mysys_err to mysys.
81
#include <mysys/my_sys.h>
1 by brian
clean slate
82
#include "m_string.h"
83
#ifndef __GNU_LIBRARY__
84
#define __GNU_LIBRARY__				// Skip warnings in getopt.h
85
#endif
86
#include <my_getopt.h>
77.1.39 by Monty Taylor
More mysql->drizzle renaming.
87
#include "drizzle_version.h"
1 by brian
clean slate
88
#include "lex.h"
89
90
const char *default_dbug_option="d:t:o,/tmp/gen_lex_hash.trace";
91
92
struct my_option my_long_options[] =
93
{
94
  {"help", '?', "Display help and exit",
95
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
96
  {"version", 'V', "Output version information and exit",
97
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
98
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
99
};
100
101
struct hash_lex_struct
102
{
103
  int first_char;
104
  char last_char;
105
  union{
106
    hash_lex_struct *char_tails;
107
    int iresult;
108
  };
109
  int ithis;
110
};
111
112
hash_lex_struct *get_hash_struct_by_len(hash_lex_struct **root_by_len,
113
					    int len, int *max_len)
114
{
115
  if (*max_len<len){
116
    *root_by_len= (hash_lex_struct *)realloc((char*)*root_by_len,
117
                                             sizeof(hash_lex_struct)*len);
118
    hash_lex_struct *cur, *end= *root_by_len + len;
119
    for (cur= *root_by_len + *max_len; cur<end; cur++)
120
      cur->first_char= 0;
121
    *max_len= len;
122
  }
123
  return (*root_by_len)+(len-1);
124
}
125
126
void insert_into_hash(hash_lex_struct *root, const char *name, 
127
		      int len_from_begin, int index, int function)
128
{
129
  hash_lex_struct *end, *cur, *tails;
130
131
  if (!root->first_char)
132
  {
133
    root->first_char= -1;
134
    root->iresult= index;
135
    return;
136
  }
137
138
  if (root->first_char == -1)
139
  {
140
    int index2= root->iresult;
141
    const char *name2= (index2 < 0 ? sql_functions[-index2-1] :
142
			symbols[index2]).name + len_from_begin;
143
    root->first_char= (int) (uchar) name2[0];
144
    root->last_char= (char) root->first_char;
145
    tails= (hash_lex_struct*)malloc(sizeof(hash_lex_struct));
146
    root->char_tails= tails;
147
    tails->first_char= -1;
148
    tails->iresult= index2;
149
  }
150
151
  size_t real_size= (root->last_char-root->first_char+1);
152
153
  if (root->first_char>(*name))
154
  {
155
    size_t new_size= root->last_char-(*name)+1;
156
    if (new_size<real_size) printf("error!!!!\n");
157
    tails= root->char_tails;
158
    tails= (hash_lex_struct*)realloc((char*)tails,
159
				       sizeof(hash_lex_struct)*new_size);
160
    root->char_tails= tails;
161
    memmove(tails+(new_size-real_size),tails,real_size*sizeof(hash_lex_struct));
162
    end= tails + new_size - real_size;
163
    for (cur= tails; cur<end; cur++)
164
      cur->first_char= 0;
165
    root->first_char= (int) (uchar) *name;
166
  }
167
168
  if (root->last_char<(*name))
169
  {
170
    size_t new_size= (*name)-root->first_char+1;
171
    if (new_size<real_size) printf("error!!!!\n");
172
    tails= root->char_tails;
173
    tails= (hash_lex_struct*)realloc((char*)tails,
174
				    sizeof(hash_lex_struct)*new_size);
175
    root->char_tails= tails;
176
    end= tails + new_size;
177
    for (cur= tails+real_size; cur<end; cur++)
178
      cur->first_char= 0;
179
    root->last_char= (*name);
180
  }
181
182
  insert_into_hash(root->char_tails+(*name)-root->first_char,
183
		   name+1,len_from_begin+1,index,function);
184
}
185
186
187
hash_lex_struct *root_by_len= 0;
188
int max_len=0;
189
190
hash_lex_struct *root_by_len2= 0;
191
int max_len2=0;
192
193
void insert_symbols()
194
{
195
  size_t i= 0;
196
  SYMBOL *cur;
197
  for (cur= symbols; i<array_elements(symbols); cur++, i++){
198
    hash_lex_struct *root= 
199
      get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
200
    insert_into_hash(root,cur->name,0,i,0);
201
  }
202
}
203
204
void insert_sql_functions()
205
{
206
  int i= 0;
207
  SYMBOL *cur;
208
  for (cur= sql_functions; i < (int) array_elements(sql_functions); cur++, i++)
209
  {
210
    hash_lex_struct *root= 
211
      get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
212
    insert_into_hash(root,cur->name,0,-i-1,1);
213
  }
214
}
215
216
void calc_length()
217
{
218
  SYMBOL *cur, *end= symbols + array_elements(symbols);
219
  for (cur= symbols; cur < end; cur++)
220
    cur->length=(uchar) strlen(cur->name);
221
  end= sql_functions + array_elements(sql_functions);
222
  for (cur= sql_functions; cur<end; cur++)
223
    cur->length=(uchar) strlen(cur->name);
224
}
225
226
void generate_find_structs()
227
{
228
  root_by_len= 0;
229
  max_len=0;
230
231
  insert_symbols();
232
233
  root_by_len2= root_by_len;
234
  max_len2= max_len;
235
236
  root_by_len= 0;
237
  max_len= 0;
238
239
  insert_symbols();
240
  insert_sql_functions();
241
}
242
243
char *hash_map= 0;
244
int size_hash_map= 0;
245
77.1.15 by Monty Taylor
Bunch of warning cleanups.
246
/* Ok. I honestly don't know why this has no problem and
247
 * array_elements macro doesn't. But it works.
248
 */
249
static inline uint32_t array_elements_func(SYMBOL * symbols) {
250
  return sizeof(symbols)/sizeof(symbols[0]);
251
}
252
1 by brian
clean slate
253
void add_struct_to_map(hash_lex_struct *st)
254
{
255
  st->ithis= size_hash_map/4;
256
  size_hash_map+= 4;
257
  hash_map= (char*)realloc((char*)hash_map,size_hash_map);
258
  hash_map[size_hash_map-4]= (char) (st->first_char == -1 ? 0 :
77.1.15 by Monty Taylor
Bunch of warning cleanups.
259
                                     st->first_char);
1 by brian
clean slate
260
  hash_map[size_hash_map-3]= (char) (st->first_char == -1 ||
77.1.15 by Monty Taylor
Bunch of warning cleanups.
261
                                     st->first_char == 0 ? 0 : st->last_char);
1 by brian
clean slate
262
  if (st->first_char == -1)
263
  {
206 by Brian Aker
Removed final uint dead types.
264
    hash_map[size_hash_map-2]= ((unsigned int)(int16_t)st->iresult)&255;
265
    hash_map[size_hash_map-1]= ((unsigned int)(int16_t)st->iresult)>>8;
1 by brian
clean slate
266
  }
267
  else if (st->first_char == 0)
268
  {
206 by Brian Aker
Removed final uint dead types.
269
    hash_map[size_hash_map-2]= ((unsigned int)(int16_t)array_elements_func(symbols))&255;
270
    hash_map[size_hash_map-1]= ((unsigned int)(int16_t)array_elements(symbols))>>8;
1 by brian
clean slate
271
  }
272
}
273
274
275
void add_structs_to_map(hash_lex_struct *st, int len)
276
{
277
  hash_lex_struct *cur, *end= st+len;
278
  for (cur= st; cur<end; cur++)
279
    add_struct_to_map(cur);
280
  for (cur= st; cur<end; cur++)
281
  {
282
    if (cur->first_char && cur->first_char != -1)
283
      add_structs_to_map(cur->char_tails,cur->last_char-cur->first_char+1);
284
  }
285
}
286
287
void set_links(hash_lex_struct *st, int len)
288
{
289
  hash_lex_struct *cur, *end= st+len;
290
  for (cur= st; cur<end; cur++)
291
  {
292
    if (cur->first_char != 0 && cur->first_char != -1)
293
    {
294
      int ilink= cur->char_tails->ithis;
295
      hash_map[cur->ithis*4+2]= ilink%256;
296
      hash_map[cur->ithis*4+3]= ilink/256;
297
      set_links(cur->char_tails,cur->last_char-cur->first_char+1);
298
    }
299
  }
300
}
301
302
303
void print_hash_map(const char *name)
304
{
305
  char *cur;
306
  int i;
307
308
  printf("static uchar %s[%d]= {\n",name,size_hash_map);
309
  for (i=0, cur= hash_map; i<size_hash_map; i++, cur++)
310
  {
311
    switch(i%4){
312
    case 0: case 1:
313
      if (!*cur)
314
	printf("0,   ");
315
      else
316
	printf("\'%c\', ",*cur);
317
      break;
318
    case 2: printf("%u, ",(uint)(uchar)*cur); break;
319
    case 3: printf("%u,\n",(uint)(uchar)*cur); break;
320
    }
321
  }
322
  printf("};\n");
323
}
324
325
326
void print_find_structs()
327
{
328
  add_structs_to_map(root_by_len,max_len);
329
  set_links(root_by_len,max_len);
330
  print_hash_map("sql_functions_map");
331
332
  hash_map= 0;
333
  size_hash_map= 0;
334
335
  printf("\n");
336
337
  add_structs_to_map(root_by_len2,max_len2);
338
  set_links(root_by_len2,max_len2);
339
  print_hash_map("symbols_map");
340
}
341
342
343
static void usage(int version)
344
{
345
  printf("%s  Ver 3.6 Distrib %s, for %s (%s)\n",
346
	 my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
347
  if (version)
348
    return;
349
  puts("Copyright (C) 2001 MySQL AB, by VVA and Monty");
350
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
351
and you are welcome to modify and redistribute it under the GPL license\n");
352
  puts("This program generates a perfect hashing function for the sql_lex.cc");
353
  printf("Usage: %s [OPTIONS]\n\n", my_progname);
354
  my_print_help(my_long_options);
355
}
356
357
143 by Brian Aker
Bool cleanup.
358
extern "C" bool
1 by brian
clean slate
359
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
360
	       char *argument __attribute__((unused)))
361
{
362
  switch(optid) {
363
  case 'V':
364
    usage(1);
365
    exit(0);
366
  case 'I':
367
  case '?':
368
    usage(0);
369
    exit(0);
370
  }
371
  return 0;
372
}
373
374
375
static int get_options(int argc, char **argv)
376
{
377
  int ho_error;
378
379
  if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option)))
380
    exit(ho_error);
381
382
  if (argc >= 1)
383
  {
384
    usage(0);
385
     exit(1);
386
  }
387
  return(0);
388
}
389
390
391
int check_dup_symbols(SYMBOL *s1, SYMBOL *s2)
392
{
393
  if (s1->length!=s2->length || strncmp(s1->name,s2->name,s1->length))
394
    return 0;
395
396
  const char *err_tmpl= "\ngen_lex_hash fatal error : \
397
Unfortunately gen_lex_hash can not generate a hash,\n since \
398
your lex.h has duplicate definition for a symbol \"%s\"\n\n";
399
  printf (err_tmpl,s1->name);
400
  fprintf (stderr,err_tmpl,s1->name);
401
402
  return 1;
403
}
404
405
406
int check_duplicates()
407
{
408
  SYMBOL *cur1, *cur2, *s_end, *f_end;
409
410
  s_end= symbols + array_elements(symbols);
411
  f_end= sql_functions + array_elements(sql_functions);
412
413
  for (cur1= symbols; cur1<s_end; cur1++)
414
  {
415
    for (cur2= cur1+1; cur2<s_end; cur2++)
416
    {
417
      if (check_dup_symbols(cur1,cur2))
418
	return 1;
419
    }
420
    for (cur2= sql_functions; cur2<f_end; cur2++)
421
    {
422
      if (check_dup_symbols(cur1,cur2))
423
	return 1;
424
    }
425
  }
426
427
  for (cur1= sql_functions; cur1<f_end; cur1++)
428
  {
429
    for (cur2= cur1+1; cur2< f_end; cur2++)
430
    {
431
      if (check_dup_symbols(cur1,cur2))
432
	return 1;
433
    }
434
  }
435
  return 0;
436
}
437
438
439
int main(int argc,char **argv)
440
{
441
  MY_INIT(argv[0]);
442
443
  if (get_options(argc,(char **) argv))
444
    exit(1);
445
446
  /* Broken up to indicate that it's not advice to you, gentle reader. */
447
  printf("/*\n\n  Do " "not " "edit " "this " "file " "directly!\n\n*/\n");
448
449
  printf("\
450
/* Copyright (C) 2001-2004 MySQL AB\n\
451
\n\
452
   This program is free software; you can redistribute it and/or modify\n\
453
   it under the terms of the GNU General Public License as published by\n\
454
   the Free Software Foundation; version 2 of the License.\n\
455
\n\
456
   This program is distributed in the hope that it will be useful,\n\
457
   but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
458
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
459
   GNU General Public License for more details.\n\
460
\n\
461
   You should have received a copy of the GNU General Public License\n\
462
   along with this program; see the file COPYING. If not, write to the\n\
463
   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston\n\
464
   MA  02110-1301  USA. */\n\
465
\n\
466
");
467
468
  /* Broken up to indicate that it's not advice to you, gentle reader. */
469
  printf("/* Do " "not " "edit " "this " "file!  This is generated by "
470
         "gen_lex_hash.cc\nthat seeks for a perfect hash function */\n\n");
471
  printf("#include \"lex.h\"\n\n");
472
473
  calc_length();
474
475
  if (check_duplicates())
476
    exit(1);
477
478
  generate_find_structs();
479
  print_find_structs();
480
481
  printf("\nstatic unsigned int sql_functions_max_len=%d;\n", max_len);
482
  printf("\nstatic unsigned int symbols_max_len=%d;\n\n", max_len2);
483
484
  printf("\
485
static SYMBOL *get_hash_symbol(const char *s,\n\
486
                               unsigned int len,bool function)\n\
487
{\n\
488
  register uchar *hash_map;\n\
489
  register const char *cur_str= s;\n\
490
\n\
491
  if (len == 0) {\n\
492
    return(NULL);\n\
493
  }\n"
494
);
495
496
  printf("\
497
  if (function){\n\
498
    if (len>sql_functions_max_len) return 0;\n\
499
    hash_map= sql_functions_map;\n\
205 by Brian Aker
uint32 -> uin32_t
500
    register uint32_t cur_struct= uint4korr(hash_map+((len-1)*4));\n\
1 by brian
clean slate
501
\n\
502
    for (;;){\n\
503
      register uchar first_char= (uchar)cur_struct;\n\
504
\n\
505
      if (first_char == 0)\n\
506
      {\n\
206 by Brian Aker
Removed final uint dead types.
507
        register int16_t ires= (int16_t)(cur_struct>>16);\n\
1 by brian
clean slate
508
        if (ires==array_elements(symbols)) return 0;\n\
509
        register SYMBOL *res;\n\
510
        if (ires>=0) \n\
511
          res= symbols+ires;\n\
512
        else\n\
513
          res= sql_functions-ires-1;\n\
514
        register uint count= cur_str-s;\n\
515
        return lex_casecmp(cur_str,res->name+count,len-count) ? 0 : res;\n\
516
      }\n\
517
\n\
518
      register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\
519
      if (cur_char<first_char) return 0;\n\
520
      cur_struct>>=8;\n\
521
      if (cur_char>(uchar)cur_struct) return 0;\n\
522
\n\
523
      cur_struct>>=8;\n\
524
      cur_struct= uint4korr(hash_map+\n\
206 by Brian Aker
Removed final uint dead types.
525
                        (((uint16_t)cur_struct + cur_char - first_char)*4));\n\
1 by brian
clean slate
526
      cur_str++;\n\
527
    }\n"
528
);
529
530
  printf("\
531
  }else{\n\
532
    if (len>symbols_max_len) return 0;\n\
533
    hash_map= symbols_map;\n\
205 by Brian Aker
uint32 -> uin32_t
534
    register uint32_t cur_struct= uint4korr(hash_map+((len-1)*4));\n\
1 by brian
clean slate
535
\n\
536
    for (;;){\n\
537
      register uchar first_char= (uchar)cur_struct;\n\
538
\n\
539
      if (first_char==0){\n\
206 by Brian Aker
Removed final uint dead types.
540
        register int16_t ires= (int16_t)(cur_struct>>16);\n\
1 by brian
clean slate
541
        if (ires==array_elements(symbols)) return 0;\n\
542
        register SYMBOL *res= symbols+ires;\n\
543
        register uint count= cur_str-s;\n\
544
        return lex_casecmp(cur_str,res->name+count,len-count)!=0 ? 0 : res;\n\
545
      }\n\
546
\n\
547
      register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\
548
      if (cur_char<first_char) return 0;\n\
549
      cur_struct>>=8;\n\
550
      if (cur_char>(uchar)cur_struct) return 0;\n\
551
\n\
552
      cur_struct>>=8;\n\
553
      cur_struct= uint4korr(hash_map+\n\
206 by Brian Aker
Removed final uint dead types.
554
                        (((uint16_t)cur_struct + cur_char - first_char)*4));\n\
1 by brian
clean slate
555
      cur_str++;\n\
556
    }\n\
557
  }\n\
558
}\n"
559
);
560
  my_end(0);
561
  exit(0);
562
}
563