You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

961 lines
24 KiB

22 years ago
  1. /* Copyright (C) 2004 MySQL AB
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
  13. // Text .frm files management routines
  14. #include "mysql_priv.h"
  15. #include <errno.h>
  16. #include <m_ctype.h>
  17. #include <my_sys.h>
  18. #include <my_dir.h>
  19. /*
  20. write string with escaping
  21. SYNOPSIS
  22. write_escaped_string()
  23. file - IO_CACHE for record
  24. val_s - string for writing
  25. RETURN
  26. FALSE - OK
  27. TRUE - error
  28. */
  29. static my_bool
  30. write_escaped_string(IO_CACHE *file, LEX_STRING *val_s)
  31. {
  32. char *eos= val_s->str + val_s->length;
  33. char *ptr= val_s->str;
  34. for (; ptr < eos; ptr++)
  35. {
  36. /*
  37. Should be in sync with read_escaped_string() and
  38. parse_quoted_escaped_string()
  39. */
  40. switch(*ptr) {
  41. case '\\': // escape character
  42. if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\\")))
  43. return TRUE;
  44. break;
  45. case '\n': // parameter value delimiter
  46. if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\n")))
  47. return TRUE;
  48. break;
  49. case '\0': // problem for some string processing utilities
  50. if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\0")))
  51. return TRUE;
  52. break;
  53. case 26: // problem for windows utilities (Ctrl-Z)
  54. if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\z")))
  55. return TRUE;
  56. break;
  57. case '\'': // list of string delimiter
  58. if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\'")))
  59. return TRUE;
  60. break;
  61. default:
  62. if (my_b_append(file, (const byte *)ptr, 1))
  63. return TRUE;
  64. }
  65. }
  66. return FALSE;
  67. }
  68. /*
  69. write parameter value to IO_CACHE
  70. SYNOPSIS
  71. write_parameter()
  72. file pointer to IO_CACHE structure for writing
  73. base pointer to data structure
  74. parameter pointer to parameter descriptor
  75. old_version for returning back old version number value
  76. RETURN
  77. FALSE - OK
  78. TRUE - error
  79. */
  80. static my_bool
  81. write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
  82. ulonglong *old_version)
  83. {
  84. char num_buf[20]; // buffer for numeric operations
  85. // string for numeric operations
  86. String num(num_buf, sizeof(num_buf), &my_charset_bin);
  87. DBUG_ENTER("write_parameter");
  88. switch (parameter->type) {
  89. case FILE_OPTIONS_STRING:
  90. {
  91. LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
  92. if (my_b_append(file, (const byte *)val_s->str, val_s->length))
  93. DBUG_RETURN(TRUE);
  94. break;
  95. }
  96. case FILE_OPTIONS_ESTRING:
  97. {
  98. if (write_escaped_string(file, (LEX_STRING *)(base + parameter->offset)))
  99. DBUG_RETURN(TRUE);
  100. break;
  101. }
  102. case FILE_OPTIONS_ULONGLONG:
  103. {
  104. num.set(*((ulonglong *)(base + parameter->offset)), &my_charset_bin);
  105. if (my_b_append(file, (const byte *)num.ptr(), num.length()))
  106. DBUG_RETURN(TRUE);
  107. break;
  108. }
  109. case FILE_OPTIONS_REV:
  110. {
  111. ulonglong *val_i= (ulonglong *)(base + parameter->offset);
  112. *old_version= (*val_i)++;
  113. num.set(*val_i, &my_charset_bin);
  114. if (my_b_append(file, (const byte *)num.ptr(), num.length()))
  115. DBUG_RETURN(TRUE);
  116. break;
  117. }
  118. case FILE_OPTIONS_TIMESTAMP:
  119. {
  120. /* string have to be allocated already */
  121. LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
  122. time_t tm= time(NULL);
  123. get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH,
  124. tm);
  125. val_s->length= PARSE_FILE_TIMESTAMPLENGTH;
  126. if (my_b_append(file, (const byte *)val_s->str,
  127. PARSE_FILE_TIMESTAMPLENGTH))
  128. DBUG_RETURN(TRUE);
  129. break;
  130. }
  131. case FILE_OPTIONS_STRLIST:
  132. {
  133. List_iterator_fast<LEX_STRING> it(*((List<LEX_STRING>*)
  134. (base + parameter->offset)));
  135. bool first= 1;
  136. LEX_STRING *str;
  137. while ((str= it++))
  138. {
  139. // We need ' ' after string to detect list continuation
  140. if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) ||
  141. my_b_append(file, (const byte *)STRING_WITH_LEN("\'")) ||
  142. write_escaped_string(file, str) ||
  143. my_b_append(file, (const byte *)STRING_WITH_LEN("\'")))
  144. {
  145. DBUG_RETURN(TRUE);
  146. }
  147. first= 0;
  148. }
  149. break;
  150. }
  151. case FILE_OPTIONS_ULLLIST:
  152. {
  153. List_iterator_fast<ulonglong> it(*((List<ulonglong>*)
  154. (base + parameter->offset)));
  155. bool first= 1;
  156. ulonglong *val;
  157. while ((val= it++))
  158. {
  159. num.set(*val, &my_charset_bin);
  160. // We need ' ' after string to detect list continuation
  161. if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) ||
  162. my_b_append(file, (const byte *)num.ptr(), num.length()))
  163. {
  164. DBUG_RETURN(TRUE);
  165. }
  166. first= 0;
  167. }
  168. break;
  169. }
  170. default:
  171. DBUG_ASSERT(0); // never should happened
  172. }
  173. DBUG_RETURN(FALSE);
  174. }
  175. /*
  176. write new .frm
  177. SYNOPSIS
  178. sql_create_definition_file()
  179. dir directory where put .frm
  180. file .frm file name
  181. type .frm type string (VIEW, TABLE)
  182. base base address for parameter reading (structure like
  183. TABLE)
  184. parameters parameters description
  185. max_versions number of versions to save
  186. RETURN
  187. FALSE - OK
  188. TRUE - error
  189. */
  190. my_bool
  191. sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
  192. const LEX_STRING *type,
  193. gptr base, File_option *parameters,
  194. uint max_versions)
  195. {
  196. File handler;
  197. IO_CACHE file;
  198. char path[FN_REFLEN+1]; // +1 to put temporary file name for sure
  199. ulonglong old_version= ULONGLONG_MAX;
  200. int path_end;
  201. File_option *param;
  202. DBUG_ENTER("sql_create_definition_file");
  203. DBUG_PRINT("enter", ("Dir: %s, file: %s, base 0x%lx",
  204. dir ? dir->str : "(null)",
  205. file_name->str, (ulong) base));
  206. if (dir)
  207. {
  208. fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME);
  209. path_end= strlen(path);
  210. }
  211. else
  212. {
  213. /*
  214. if not dir is passed, it means file_name is a full path,
  215. including dir name, file name itself, and an extension,
  216. and with unpack_filename() executed over it.
  217. */
  218. path_end= strxnmov(path, FN_REFLEN, file_name->str, NullS) - path;
  219. }
  220. // temporary file name
  221. path[path_end]='~';
  222. path[path_end+1]= '\0';
  223. if ((handler= my_create(path, CREATE_MODE, O_RDWR | O_TRUNC,
  224. MYF(MY_WME))) <= 0)
  225. {
  226. DBUG_RETURN(TRUE);
  227. }
  228. if (init_io_cache(&file, handler, 0, SEQ_READ_APPEND, 0L, 0, MYF(MY_WME)))
  229. goto err_w_file;
  230. // write header (file signature)
  231. if (my_b_append(&file, (const byte *)STRING_WITH_LEN("TYPE=")) ||
  232. my_b_append(&file, (const byte *)type->str, type->length) ||
  233. my_b_append(&file, (const byte *)STRING_WITH_LEN("\n")))
  234. goto err_w_file;
  235. // write parameters to temporary file
  236. for (param= parameters; param->name.str; param++)
  237. {
  238. if (my_b_append(&file, (const byte *)param->name.str,
  239. param->name.length) ||
  240. my_b_append(&file, (const byte *)STRING_WITH_LEN("=")) ||
  241. write_parameter(&file, base, param, &old_version) ||
  242. my_b_append(&file, (const byte *)STRING_WITH_LEN("\n")))
  243. goto err_w_cache;
  244. }
  245. if (end_io_cache(&file))
  246. goto err_w_file;
  247. if (my_close(handler, MYF(MY_WME)))
  248. {
  249. DBUG_RETURN(TRUE);
  250. }
  251. // archive copies management
  252. path[path_end]='\0';
  253. if (!access(path, F_OK))
  254. {
  255. if (old_version != ULONGLONG_MAX && max_versions != 0)
  256. {
  257. // save backup
  258. char path_arc[FN_REFLEN];
  259. // backup old version
  260. char path_to[FN_REFLEN];
  261. // check archive directory existence
  262. fn_format(path_arc, "arc", dir->str, "", MY_UNPACK_FILENAME);
  263. if (access(path_arc, F_OK))
  264. {
  265. if (my_mkdir(path_arc, 0777, MYF(MY_WME)))
  266. {
  267. DBUG_RETURN(TRUE);
  268. }
  269. }
  270. my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lu",
  271. path_arc, file_name->str, (ulong) old_version);
  272. if (my_rename(path, path_to, MYF(MY_WME)))
  273. {
  274. DBUG_RETURN(TRUE);
  275. }
  276. // remove very old version
  277. if (old_version > max_versions)
  278. {
  279. my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lu",
  280. path_arc, file_name->str,
  281. (ulong)(old_version - max_versions));
  282. if (!access(path_arc, F_OK) && my_delete(path_to, MYF(MY_WME)))
  283. {
  284. DBUG_RETURN(TRUE);
  285. }
  286. }
  287. }
  288. else
  289. {
  290. if (my_delete(path, MYF(MY_WME))) // no backups
  291. {
  292. DBUG_RETURN(TRUE);
  293. }
  294. }
  295. }
  296. {
  297. // rename temporary file
  298. char path_to[FN_REFLEN];
  299. memcpy(path_to, path, path_end+1);
  300. path[path_end]='~';
  301. if (my_rename(path, path_to, MYF(MY_WME)))
  302. {
  303. DBUG_RETURN(TRUE);
  304. }
  305. }
  306. DBUG_RETURN(FALSE);
  307. err_w_cache:
  308. end_io_cache(&file);
  309. err_w_file:
  310. my_close(handler, MYF(MY_WME));
  311. DBUG_RETURN(TRUE);
  312. }
  313. /*
  314. Renames a frm file (including backups) in same schema
  315. SYNOPSIS
  316. rename_in_schema_file
  317. schema name of given schema
  318. old_name original file name
  319. new_name new file name
  320. revision revision number
  321. num_view_backups number of backups
  322. RETURN
  323. 0 - OK
  324. 1 - Error (only if renaming of frm failed)
  325. */
  326. my_bool rename_in_schema_file(const char *schema, const char *old_name,
  327. const char *new_name, ulonglong revision,
  328. uint num_view_backups)
  329. {
  330. char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN];
  331. strxnmov(old_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/",
  332. old_name, reg_ext, NullS);
  333. (void) unpack_filename(old_path, old_path);
  334. strxnmov(new_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/",
  335. new_name, reg_ext, NullS);
  336. (void) unpack_filename(new_path, new_path);
  337. if (my_rename(old_path, new_path, MYF(MY_WME)))
  338. return 1;
  339. /* check if arc_dir exists */
  340. strxnmov(arc_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/arc", NullS);
  341. (void) unpack_filename(arc_path, arc_path);
  342. if (revision > 0 && !access(arc_path, F_OK))
  343. {
  344. ulonglong limit= ((revision > num_view_backups) ?
  345. revision - num_view_backups : 0);
  346. for (; revision > limit ; revision--)
  347. {
  348. my_snprintf(old_path, FN_REFLEN, "%s/%s%s-%04lu",
  349. arc_path, old_name, reg_ext, (ulong)revision);
  350. (void) unpack_filename(old_path, old_path);
  351. my_snprintf(new_path, FN_REFLEN, "%s/%s%s-%04lu",
  352. arc_path, new_name, reg_ext, (ulong)revision);
  353. (void) unpack_filename(new_path, new_path);
  354. my_rename(old_path, new_path, MYF(0));
  355. }
  356. }
  357. return 0;
  358. }
  359. /*
  360. Prepare frm to parse (read to memory)
  361. SYNOPSIS
  362. sql_parse_prepare()
  363. file_name - path & filename to .frm file
  364. mem_root - MEM_ROOT for buffer allocation
  365. bad_format_errors - send errors on bad content
  366. RETURN
  367. 0 - error
  368. parser object
  369. NOTE
  370. returned pointer + 1 will be type of .frm
  371. */
  372. File_parser *
  373. sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
  374. bool bad_format_errors)
  375. {
  376. MY_STAT stat_info;
  377. uint len;
  378. char *end, *sign;
  379. File_parser *parser;
  380. File file;
  381. DBUG_ENTER("sql_parse_prepare");
  382. if (!my_stat(file_name->str, &stat_info, MYF(MY_WME)))
  383. {
  384. DBUG_RETURN(0);
  385. }
  386. if (stat_info.st_size > INT_MAX-1)
  387. {
  388. my_error(ER_FPARSER_TOO_BIG_FILE, MYF(0), file_name->str);
  389. DBUG_RETURN(0);
  390. }
  391. if (!(parser= new(mem_root) File_parser))
  392. {
  393. DBUG_RETURN(0);
  394. }
  395. if (!(parser->buff= alloc_root(mem_root, stat_info.st_size+1)))
  396. {
  397. DBUG_RETURN(0);
  398. }
  399. if ((file= my_open(file_name->str, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
  400. {
  401. DBUG_RETURN(0);
  402. }
  403. if ((len= my_read(file, (byte *)parser->buff,
  404. stat_info.st_size, MYF(MY_WME))) ==
  405. MY_FILE_ERROR)
  406. {
  407. my_close(file, MYF(MY_WME));
  408. DBUG_RETURN(0);
  409. }
  410. if (my_close(file, MYF(MY_WME)))
  411. {
  412. DBUG_RETURN(0);
  413. }
  414. end= parser->end= parser->buff + len;
  415. *end= '\0'; // barrier for more simple parsing
  416. // 7 = 5 (TYPE=) + 1 (letter at least of type name) + 1 ('\n')
  417. if (len < 7 ||
  418. parser->buff[0] != 'T' ||
  419. parser->buff[1] != 'Y' ||
  420. parser->buff[2] != 'P' ||
  421. parser->buff[3] != 'E' ||
  422. parser->buff[4] != '=')
  423. goto frm_error;
  424. // skip signature;
  425. parser->file_type.str= sign= parser->buff + 5;
  426. while (*sign >= 'A' && *sign <= 'Z' && sign < end)
  427. sign++;
  428. if (*sign != '\n')
  429. goto frm_error;
  430. parser->file_type.length= sign - parser->file_type.str;
  431. // EOS for file signature just for safety
  432. *sign= '\0';
  433. parser->start= sign + 1;
  434. parser->content_ok= 1;
  435. DBUG_RETURN(parser);
  436. frm_error:
  437. if (bad_format_errors)
  438. {
  439. my_error(ER_FPARSER_BAD_HEADER, MYF(0), file_name->str);
  440. DBUG_RETURN(0);
  441. }
  442. else
  443. DBUG_RETURN(parser); // upper level have to check parser->ok()
  444. }
  445. /*
  446. parse LEX_STRING
  447. SYNOPSIS
  448. parse_string()
  449. ptr - pointer on string beginning
  450. end - pointer on symbol after parsed string end (still owned
  451. by buffer and can be accessed
  452. mem_root - MEM_ROOT for parameter allocation
  453. str - pointer on string, where results should be stored
  454. RETURN
  455. 0 - error
  456. # - pointer on symbol after string
  457. */
  458. static char *
  459. parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
  460. {
  461. // get string length
  462. char *eol= strchr(ptr, '\n');
  463. if (eol >= end)
  464. return 0;
  465. str->length= eol - ptr;
  466. if (!(str->str= alloc_root(mem_root, str->length+1)))
  467. return 0;
  468. memcpy(str->str, ptr, str->length);
  469. str->str[str->length]= '\0'; // just for safety
  470. return eol+1;
  471. }
  472. /*
  473. read escaped string from ptr to eol in already allocated str
  474. SYNOPSIS
  475. read_escaped_string()
  476. ptr - pointer on string beginning
  477. eol - pointer on character after end of string
  478. str - target string
  479. RETURN
  480. FALSE - OK
  481. TRUE - error
  482. */
  483. my_bool
  484. read_escaped_string(char *ptr, char *eol, LEX_STRING *str)
  485. {
  486. char *write_pos= str->str;
  487. for (; ptr < eol; ptr++, write_pos++)
  488. {
  489. char c= *ptr;
  490. if (c == '\\')
  491. {
  492. ptr++;
  493. if (ptr >= eol)
  494. return TRUE;
  495. /*
  496. Should be in sync with write_escaped_string() and
  497. parse_quoted_escaped_string()
  498. */
  499. switch(*ptr) {
  500. case '\\':
  501. *write_pos= '\\';
  502. break;
  503. case 'n':
  504. *write_pos= '\n';
  505. break;
  506. case '0':
  507. *write_pos= '\0';
  508. break;
  509. case 'z':
  510. *write_pos= 26;
  511. break;
  512. case '\'':
  513. *write_pos= '\'';
  514. break;
  515. default:
  516. return TRUE;
  517. }
  518. }
  519. else
  520. *write_pos= c;
  521. }
  522. str->str[str->length= write_pos-str->str]= '\0'; // just for safety
  523. return FALSE;
  524. }
  525. /*
  526. parse \n delimited escaped string
  527. SYNOPSIS
  528. parse_escaped_string()
  529. ptr - pointer on string beginning
  530. end - pointer on symbol after parsed string end (still owned
  531. by buffer and can be accessed
  532. mem_root - MEM_ROOT for parameter allocation
  533. str - pointer on string, where results should be stored
  534. RETURN
  535. 0 - error
  536. # - pointer on symbol after string
  537. */
  538. char *
  539. parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
  540. {
  541. char *eol= strchr(ptr, '\n');
  542. if (eol == 0 || eol >= end ||
  543. !(str->str= alloc_root(mem_root, (eol - ptr) + 1)) ||
  544. read_escaped_string(ptr, eol, str))
  545. return 0;
  546. return eol+1;
  547. }
  548. /*
  549. parse '' delimited escaped string
  550. SYNOPSIS
  551. parse_quoted_escaped_string()
  552. ptr - pointer on string beginning
  553. end - pointer on symbol after parsed string end (still owned
  554. by buffer and can be accessed
  555. mem_root - MEM_ROOT for parameter allocation
  556. str - pointer on string, where results should be stored
  557. RETURN
  558. 0 - error
  559. # - pointer on symbol after string
  560. */
  561. static char *
  562. parse_quoted_escaped_string(char *ptr, char *end,
  563. MEM_ROOT *mem_root, LEX_STRING *str)
  564. {
  565. char *eol;
  566. uint result_len= 0;
  567. bool escaped= 0;
  568. // starting '
  569. if (*(ptr++) != '\'')
  570. return 0;
  571. // find ending '
  572. for (eol= ptr; (*eol != '\'' || escaped) && eol < end; eol++)
  573. {
  574. if (!(escaped= (*eol == '\\' && !escaped)))
  575. result_len++;
  576. }
  577. // process string
  578. if (eol >= end ||
  579. !(str->str= alloc_root(mem_root, result_len + 1)) ||
  580. read_escaped_string(ptr, eol, str))
  581. return 0;
  582. return eol+1;
  583. }
  584. /*
  585. Parser for FILE_OPTIONS_ULLLIST type value.
  586. SYNOPSIS
  587. get_file_options_ulllist()
  588. ptr [in/out] pointer to parameter
  589. end [in] end of the configuration
  590. line [in] pointer to the line begining
  591. base [in] base address for parameter writing (structure
  592. like TABLE)
  593. parameter [in] description
  594. mem_root [in] MEM_ROOT for parameters allocation
  595. */
  596. bool get_file_options_ulllist(char *&ptr, char *end, char *line,
  597. gptr base, File_option *parameter,
  598. MEM_ROOT *mem_root)
  599. {
  600. List<ulonglong> *nlist= (List<ulonglong>*)(base + parameter->offset);
  601. ulonglong *num;
  602. nlist->empty();
  603. // list parsing
  604. while (ptr < end)
  605. {
  606. int not_used;
  607. char *num_end= end;
  608. if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) ||
  609. nlist->push_back(num, mem_root))
  610. goto nlist_err;
  611. *num= my_strtoll10(ptr, &num_end, &not_used);
  612. ptr= num_end;
  613. switch (*ptr) {
  614. case '\n':
  615. goto end_of_nlist;
  616. case ' ':
  617. // we cant go over buffer bounds, because we have \0 at the end
  618. ptr++;
  619. break;
  620. default:
  621. goto nlist_err_w_message;
  622. }
  623. }
  624. end_of_nlist:
  625. if (*(ptr++) != '\n')
  626. goto nlist_err;
  627. return FALSE;
  628. nlist_err_w_message:
  629. my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), parameter->name.str, line);
  630. nlist_err:
  631. return TRUE;
  632. }
  633. /*
  634. parse parameters
  635. SYNOPSIS
  636. File_parser::parse()
  637. base base address for parameter writing (structure like
  638. TABLE)
  639. mem_root MEM_ROOT for parameters allocation
  640. parameters parameters description
  641. required number of required parameters in above list
  642. hook hook called for unknown keys
  643. hook_data some data specific for the hook
  644. RETURN
  645. FALSE - OK
  646. TRUE - error
  647. */
  648. my_bool
  649. File_parser::parse(gptr base, MEM_ROOT *mem_root,
  650. struct File_option *parameters, uint required,
  651. Unknown_key_hook *hook)
  652. {
  653. uint first_param= 0, found= 0;
  654. char *ptr= start;
  655. char *eol;
  656. LEX_STRING *str;
  657. List<LEX_STRING> *list;
  658. DBUG_ENTER("File_parser::parse");
  659. while (ptr < end && found < required)
  660. {
  661. char *line= ptr;
  662. if (*ptr == '#')
  663. {
  664. // it is comment
  665. if (!(ptr= strchr(ptr, '\n')))
  666. {
  667. my_error(ER_FPARSER_EOF_IN_COMMENT, MYF(0), line);
  668. DBUG_RETURN(TRUE);
  669. }
  670. ptr++;
  671. }
  672. else
  673. {
  674. File_option *parameter= parameters+first_param,
  675. *parameters_end= parameters+required;
  676. int len= 0;
  677. for (; parameter < parameters_end; parameter++)
  678. {
  679. len= parameter->name.length;
  680. // check length
  681. if (len < (end-ptr) && ptr[len] != '=')
  682. continue;
  683. // check keyword
  684. if (memcmp(parameter->name.str, ptr, len) == 0)
  685. break;
  686. }
  687. if (parameter < parameters_end)
  688. {
  689. found++;
  690. /*
  691. if we found first parameter, start search from next parameter
  692. next time.
  693. (this small optimisation should work, because they should be
  694. written in same order)
  695. */
  696. if (parameter == parameters+first_param)
  697. first_param++;
  698. // get value
  699. ptr+= (len+1);
  700. switch (parameter->type) {
  701. case FILE_OPTIONS_STRING:
  702. {
  703. if (!(ptr= parse_string(ptr, end, mem_root,
  704. (LEX_STRING *)(base +
  705. parameter->offset))))
  706. {
  707. my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
  708. parameter->name.str, line);
  709. DBUG_RETURN(TRUE);
  710. }
  711. break;
  712. }
  713. case FILE_OPTIONS_ESTRING:
  714. {
  715. if (!(ptr= parse_escaped_string(ptr, end, mem_root,
  716. (LEX_STRING *)
  717. (base + parameter->offset))))
  718. {
  719. my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
  720. parameter->name.str, line);
  721. DBUG_RETURN(TRUE);
  722. }
  723. break;
  724. }
  725. case FILE_OPTIONS_ULONGLONG:
  726. case FILE_OPTIONS_REV:
  727. if (!(eol= strchr(ptr, '\n')))
  728. {
  729. my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
  730. parameter->name.str, line);
  731. DBUG_RETURN(TRUE);
  732. }
  733. {
  734. int not_used;
  735. *((ulonglong*)(base + parameter->offset))=
  736. my_strtoll10(ptr, 0, &not_used);
  737. }
  738. ptr= eol+1;
  739. break;
  740. case FILE_OPTIONS_TIMESTAMP:
  741. {
  742. /* string have to be allocated already */
  743. LEX_STRING *val= (LEX_STRING *)(base + parameter->offset);
  744. /* yyyy-mm-dd HH:MM:SS = 19(PARSE_FILE_TIMESTAMPLENGTH) characters */
  745. if (ptr[PARSE_FILE_TIMESTAMPLENGTH] != '\n')
  746. {
  747. my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
  748. parameter->name.str, line);
  749. DBUG_RETURN(TRUE);
  750. }
  751. memcpy(val->str, ptr, PARSE_FILE_TIMESTAMPLENGTH);
  752. val->str[val->length= PARSE_FILE_TIMESTAMPLENGTH]= '\0';
  753. ptr+= (PARSE_FILE_TIMESTAMPLENGTH+1);
  754. break;
  755. }
  756. case FILE_OPTIONS_STRLIST:
  757. {
  758. list= (List<LEX_STRING>*)(base + parameter->offset);
  759. list->empty();
  760. // list parsing
  761. while (ptr < end)
  762. {
  763. if (!(str= (LEX_STRING*)alloc_root(mem_root,
  764. sizeof(LEX_STRING))) ||
  765. list->push_back(str, mem_root))
  766. goto list_err;
  767. if (!(ptr= parse_quoted_escaped_string(ptr, end, mem_root, str)))
  768. goto list_err_w_message;
  769. switch (*ptr) {
  770. case '\n':
  771. goto end_of_list;
  772. case ' ':
  773. // we cant go over buffer bounds, because we have \0 at the end
  774. ptr++;
  775. break;
  776. default:
  777. goto list_err_w_message;
  778. }
  779. }
  780. end_of_list:
  781. if (*(ptr++) != '\n')
  782. goto list_err;
  783. break;
  784. list_err_w_message:
  785. my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
  786. parameter->name.str, line);
  787. list_err:
  788. DBUG_RETURN(TRUE);
  789. }
  790. case FILE_OPTIONS_ULLLIST:
  791. if (get_file_options_ulllist(ptr, end, line, base,
  792. parameter, mem_root))
  793. DBUG_RETURN(TRUE);
  794. break;
  795. default:
  796. DBUG_ASSERT(0); // never should happened
  797. }
  798. }
  799. else
  800. {
  801. ptr= line;
  802. if (hook->process_unknown_string(ptr, base, mem_root, end))
  803. {
  804. DBUG_RETURN(TRUE);
  805. }
  806. // skip unknown parameter
  807. if (!(ptr= strchr(ptr, '\n')))
  808. {
  809. my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0), line);
  810. DBUG_RETURN(TRUE);
  811. }
  812. ptr++;
  813. }
  814. }
  815. }
  816. DBUG_RETURN(FALSE);
  817. }
  818. /*
  819. Dummy unknown key hook
  820. SYNOPSIS
  821. File_parser_dummy_hook::process_unknown_string()
  822. unknown_key [in/out] reference on the line with unknown
  823. parameter and the parsing point
  824. base [in] base address for parameter writing (structure like
  825. TABLE)
  826. mem_root [in] MEM_ROOT for parameters allocation
  827. end [in] the end of the configuration
  828. NOTE
  829. This hook used to catch no longer supported keys and process them for
  830. backward compatibility, but it will not slow down processing of modern
  831. format files.
  832. This hook does nothing except debug output.
  833. RETURN
  834. FALSE OK
  835. TRUE Error
  836. */
  837. bool
  838. File_parser_dummy_hook::process_unknown_string(char *&unknown_key,
  839. gptr base, MEM_ROOT *mem_root,
  840. char *end)
  841. {
  842. DBUG_ENTER("file_parser_dummy_hook::process_unknown_string");
  843. DBUG_PRINT("info", ("Unknown key: '%60s'", unknown_key));
  844. DBUG_RETURN(FALSE);
  845. }