CUBRID Engine  latest
csql_support.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * csql_support.c : Utilities for csql module
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <signal.h>
30 #include <setjmp.h>
31 #include <assert.h>
32 #if defined(WINDOWS)
33 #include <io.h>
34 #else /* !WINDOWS */
35 #include <pwd.h>
36 #endif /* !WINDOWS */
37 #include "porting.h"
38 #include "csql.h"
39 #include "filesys.hpp"
40 #include "filesys_temp.hpp"
41 #include "memory_alloc.h"
42 #include "system_parameter.h"
43 #include "ddl_log.h"
44 
45 #if defined (SUPPRESS_STRLEN_WARNING)
46 #define strlen(s1) ((int) strlen(s1))
47 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
48 
49 /* fixed stop position of a tab */
50 #define TAB_STOP 8
51 
52 /* number of lines at each expansion of more line pointer array */
53 #define MORE_LINE_EXPANSION_UNIT 40
54 
55 /* to build the current help message lines */
56 static char **iq_More_lines; /* more message lines */
57 static int iq_Num_more_lines = 0; /* number of more lines */
58 static jmp_buf iq_Jmp_buf;
59 
60 #define DEFAULT_DB_ERROR_MSG_LEVEL 3 /* current max */
61 
63 {
75 
76 /* editor buffer management */
77 typedef struct
78 {
79  char *contents;
80  int data_size;
84 
86 
87 
88 static void iq_pipe_handler (int sig_no);
89 static void iq_format_err (char *string, int buf_size, int line_no, int col_no);
90 static bool iq_input_device_is_a_tty (void);
91 static bool iq_output_device_is_a_tty (void);
92 #if !defined(WINDOWS)
93 static int csql_get_user_home (char *homebuf, int bufsize);
94 #endif /* !WINDOWS */
95 
96 /*
97  * iq_output_device_is_a_tty() - return if output stream is associated with
98  * a "tty" device.
99  * return: true if the output device is a terminal
100  */
101 static bool
103 {
104  return (csql_Output_fp == stdout && isatty (fileno (stdout)));
105 }
106 
107 /*
108  * iq_input_device_is_a_tty() - return if input stream is associated with
109  * a "tty" device.
110  * return: true if the input device is a terminal
111  */
112 static bool
114 {
115  return (csql_Input_fp == stdin && isatty (fileno (stdin)));
116 }
117 
118 #if !defined(WINDOWS)
119 /*
120  * csql_get_user_home() - get user home directory from /etc/passwd file
121  * return: 0 if success, -1 otherwise
122  * homedir(in/out) : user home directory
123  * homedir_size(in) : size of homedir buffer
124  */
125 static int
126 csql_get_user_home (char *homedir, int homedir_size)
127 {
128  struct passwd *ptr = NULL;
129  uid_t userid = getuid ();
130 
131  setpwent ();
132 
133  while ((ptr = getpwent ()) != NULL)
134  {
135  if (userid == ptr->pw_uid)
136  {
137  snprintf (homedir, homedir_size, "%s", ptr->pw_dir);
138  endpwent ();
139  return NO_ERROR;
140  }
141  }
142  endpwent ();
143  return ER_FAILED;
144 }
145 #endif /* !WINDOWS */
146 
147 /*
148  * csql_get_real_path() - get the real pathname (without wild/meta chars) using
149  * the default shell
150  * return: the real path name
151  * pathname(in)
152  *
153  * Note:
154  * the real path name returned from this function is valid until next this
155  * function call. The return string will not have any leading/trailing
156  * characters other than the path name itself. If error occurred from O.S,
157  * give up the extension and just return the `pathname'.
158  */
159 char *
160 csql_get_real_path (const char *pathname)
161 {
162 #if defined(WINDOWS)
163  if (pathname == NULL)
164  {
165  return NULL;
166  }
167 
168  while (isspace (pathname[0]))
169  {
170  pathname++;
171  }
172 
173  if (pathname[0] == '\0')
174  {
175  return NULL;
176  }
177 
178  return (char *) pathname;
179 #else /* ! WINDOWS */
180  static char real_path[PATH_MAX]; /* real path name */
181  char home[PATH_MAX];
182 
183  if (pathname == NULL)
184  {
185  return NULL;
186  }
187 
188  while (isspace (pathname[0]))
189  {
190  pathname++;
191  }
192 
193  if (pathname[0] == '\0')
194  {
195  return NULL;
196  }
197 
198  /*
199  * Do tilde-expansion here.
200  */
201  if (pathname[0] == '~')
202  {
203  if (csql_get_user_home (home, sizeof (home)) != NO_ERROR)
204  {
205  return NULL;
206  }
207 
208  snprintf (real_path, sizeof (real_path), "%s%s", home, &pathname[1]);
209  }
210  else
211  {
212  snprintf (real_path, sizeof (real_path), "%s", pathname);
213  }
214 
215  return real_path;
216 #endif /* !WINDOWS */
217 }
218 
219 /*
220  * csql_invoke_system() - execute the given command with the argument using
221  * system()
222  * return: none
223  * command(in)
224  */
225 void
226 csql_invoke_system (const char *command)
227 {
228  bool error_found = false; /* TRUE if error found */
229 
230  if (system (command) == 127)
231  {
232  error_found = true;
234  }
235 
236  if (error_found)
237  {
239  }
240 }
241 
242 /*
243  * csql_invoke_system_editor()
244  * return: CSQL_SUCCESS/CSQL_FAILURE
245  *
246  * Note:
247  * copy command editor buffer into temporary file and
248  * invoke the user preferred system editor. After the
249  * edit is finished, read the file into editor buffer
250  */
251 int
253 {
255  {
258  return CSQL_FAILURE;
259  }
260 
261  /* create an unique file in tmp folder and open it for writing */
262  auto[filename, fileptr] = filesys::open_temp_file ("csql_");
263  if (fileptr == NULL)
264  {
267  return CSQL_FAILURE;
268  }
269  filesys::auto_delete_file file_del (filename.c_str ()); //deletes file at scope end
270  filesys::auto_close_file file (fileptr); //closes file at scope end (before the above file deleter); forget about fp from now on
271 
272  /* write the content of editor to the temp file */
273  if (csql_edit_write_file (file.get ()) == CSQL_FAILURE)
274  {
276  return CSQL_FAILURE;
277  }
278 
279  /* invoke the system editor */
280  char *cmd = csql_get_tmp_buf (strlen (csql_Editor_cmd + 1 + filename.size ()));
281  if (cmd == NULL)
282  {
284  return CSQL_FAILURE;
285  }
286  fclose (file.release ()); //on Windows needs to be closed before being able to save from Notepad
287  sprintf (cmd, "%s %s", csql_Editor_cmd, filename.c_str ());
288  csql_invoke_system (cmd);
289 
290  /* initialize editor buffer */
292 
293  file.reset (fopen (filename.c_str (), "r"));
294  if (!file)
295  {
298  return CSQL_FAILURE;
299  }
300 
301  /* read the temp file into editor */
302  if (csql_edit_read_file (file.get ()) == CSQL_FAILURE)
303  {
305  return CSQL_FAILURE;
306  }
307 
308  return CSQL_SUCCESS;
309 }
310 
311 /*
312  * csql_fputs()
313  * return: none
314  * str(in): string to be displayed
315  * fp(in) : FILE stream
316  *
317  * Note:
318  * `fputs' version to cope with "\1" in the string. This function displays
319  * `<', `>' alternatively.
320  */
321 void
322 csql_fputs (const char *str, FILE * fp)
323 {
324  bool flag; /* toggled at every "\1" */
325 
326  if (!fp)
327  {
328  return;
329  }
330 
331  for (flag = false; *str != '\0'; str++)
332  {
333  if (*str == '\1')
334  {
335  putc ((flag) ? '>' : '<', fp);
336  flag = !flag;
337  }
338  else
339  {
340  putc (*str, fp);
341  }
342  }
343 }
344 
345 /*
346  * csql_fputs_console_conv() - format and display a string to the CSQL console
347  * with console conversion applied, if available
348  * return: none
349  * str(in): string to be displayed
350  * fp(in) : FILE stream
351  *
352  * Note:
353  * `fputs' version to cope with "\1" in the string. This function displays
354  * `<', `>' alternatively.
355  */
356 void
357 csql_fputs_console_conv (const char *str, FILE * fp)
358 {
359  char *conv_buf = NULL;
360  const char *conv_buf_ptr = NULL;
361  int conv_buf_size = 0;
362 
363  if (!fp)
364  {
365  return;
366  }
367 
369  && (*csql_text_utf8_to_console) (str, strlen (str), &conv_buf, &conv_buf_size) == NO_ERROR && conv_buf != NULL)
370  {
371  conv_buf_ptr = conv_buf;
372  }
373  else
374  {
375  conv_buf_ptr = str;
376  }
377 
378  csql_fputs (conv_buf_ptr, fp);
379 
380  if (conv_buf != NULL)
381  {
382  free (conv_buf);
383  }
384 }
385 
386 /*
387  * csql_popen() - Open & return a pipe file stream to a pager
388  * return: pipe file stream to a pager if stdout is a tty,
389  * otherwise return fd.
390  * cmd(in) : popen command
391  * fd(in): currently open file descriptor
392  *
393  * Note: Caller should call csql_pclose() after done.
394  */
395 FILE *
396 csql_popen (const char *cmd, FILE * fd)
397 {
398 
399 #if defined(WINDOWS)
400  /* Nothing yet currently equivalent to the pagers on NT. Return iq_Output_fp so it can be simply sump stuff to the
401  * console. */
402  return fd;
403 #else /* ! WINDOWS */
404  FILE *pf; /* pipe stream to pager */
405 
406  pf = fd;
407  if (cmd == NULL || cmd[0] == '\0')
408  {
409  return pf;
410  }
411 
413  {
414  pf = popen (cmd, "w");
415  if (pf == NULL)
416  { /* pager failed, */
419  pf = fd;
420  }
421  }
422  else
423  {
424  pf = fd;
425  }
426 
427  return (pf);
428 #endif /* ! WINDOWS */
429 }
430 
431 /*
432  * csql_pclose(): close pipe file stream
433  * return: none
434  * pf(in): pipe stream pointer
435  * fd(in): This is the file descriptor for the output stream
436  * which was open prior to calling csql_popen().
437  *
438  * Note:
439  * We determine if it's a pipe by comparing the pipe stream pointer (pf)
440  * with the prior file descriptor (fd). If they are different, then a pipe
441  * was opened and will be closed.
442  */
443 void
444 csql_pclose (FILE * pf, FILE * fd)
445 {
446 #if !defined(WINDOWS)
447  if (pf != fd)
448  {
449  pclose (pf);
450  }
451 #endif /* ! WINDOWS */
452 }
453 
454 /*
455  * iq_format_err() - format an error string with line and/or column number
456  * return: none
457  * string(out): output string buffer
458  * line_no(in): error line number
459  * col_no(in) : error column number
460  */
461 static void
462 iq_format_err (char *string, int buf_size, int line_no, int col_no)
463 {
464  if (line_no > 0)
465  {
466  if (col_no > 0)
467  snprintf (string, buf_size,
469  col_no);
470  else
471  snprintf (string, buf_size,
473  strcat (string, "\n");
474  }
475 }
476 
477 /*
478  * csql_display_csql_err() - display error message
479  * return: none
480  * line_no(in): error line number
481  * col_no(in) : error column number
482  *
483  * Note:
484  * if `line_no' is positive, this error is regarded as associated with
485  * the given line number. if `col_no' is positive, it represents the
486  * error position represents the exact position, otherwise it tells where
487  * the stmt starts.
488  */
489 void
490 csql_display_csql_err (int line_no, int col_no)
491 {
493 
495 
496  if (line_no > 0)
497  {
498  csql_fputs ("\n", csql_Error_fp);
500  }
502 }
503 
504 /*
505  * csql_display_session_err() - display all query compilation errors
506  * for this session
507  * return: none
508  * session(in): context of query compilation
509  * line_no(in): statement starting line number
510  */
511 void
512 csql_display_session_err (DB_SESSION * session, int line_no)
513 {
515  int col_no = 0;
516 
518 
519  err = db_get_errors (session);
520 
521  do
522  {
523  err = db_get_next_error (err, &line_no, &col_no);
524  if (line_no > 0)
525  {
526  csql_fputs ("\n", csql_Error_fp);
529  }
531  }
532  while (err);
533 
534  return;
535 }
536 
537 /*
538  * csql_append_more_line() - append the given line into the
539  * more message line array
540  * return: CSQL_FAILURE/CSQL_SUCCESS
541  * indent(in): number of blanks to be prefixed
542  * line(in): new line to be put
543  *
544  * Note:
545  * After usage of the more lines, caller should free by calling
546  * free_more_lines(). The line cannot have control characters except tab,
547  * new-line and "\1".
548  */
549 int
550 csql_append_more_line (int indent, const char *line)
551 {
552  int i, j;
553  int n; /* register copy of num_more_lines */
554  int exp_len; /* length of lines after tab expand */
555  int new_num; /* new # of entries */
556  char *p;
557  const char *q;
558  char **t_lines; /* temp pointer */
559  char *conv_buf = NULL;
560  int conv_buf_size = 0;
561 
563  && (*csql_text_utf8_to_console) (line, strlen (line), &conv_buf, &conv_buf_size) == NO_ERROR)
564  {
565  line = (conv_buf != NULL) ? conv_buf : line;
566  }
567  else
568  {
569  assert (conv_buf == NULL);
570  }
571 
572  n = iq_Num_more_lines;
573 
574  if (n % MORE_LINE_EXPANSION_UNIT == 0)
575  {
576  new_num = n + MORE_LINE_EXPANSION_UNIT;
577  if (n == 0)
578  {
579  t_lines = (char **) malloc (sizeof (char *) * new_num);
580  }
581  else
582  {
583  t_lines = (char **) realloc (iq_More_lines, sizeof (char *) * new_num);
584  }
585  if (t_lines == NULL)
586  {
588  if (conv_buf != NULL)
589  {
591  free_and_init (conv_buf);
592  }
593  return (CSQL_FAILURE);
594  }
595  iq_More_lines = t_lines;
596  }
597 
598  /* calculate # of bytes should be allocated to store the given line in tab-expanded form */
599  for (i = exp_len = 0, q = line; *q != '\0'; q++)
600  {
601  if (*q == '\n')
602  {
603  exp_len += i + 1;
604  i = 0;
605  }
606  else if (*q == '\t')
607  {
608  i += TAB_STOP - i % TAB_STOP;
609  }
610  else
611  {
612  i++;
613  }
614  }
615  exp_len += i + 1;
616 
617  iq_More_lines[n] = (char *) malloc (indent + exp_len);
618  if (iq_More_lines[n] == NULL)
619  {
621  if (conv_buf != NULL)
622  {
624  free_and_init (conv_buf);
625  }
626  return (CSQL_FAILURE);
627  }
628  for (i = 0, p = iq_More_lines[n]; i < indent; i++)
629  {
630  *p++ = ' ';
631  }
632 
633  /* copy the line with tab expansion */
634  for (i = 0, q = line; *q != '\0'; q++)
635  {
636  if (*q == '\n')
637  {
638  *p++ = *q;
639  i = 0;
640  }
641  else if (*q == '\t')
642  {
643  for (j = TAB_STOP - i % TAB_STOP; j > 0; j--, i++)
644  {
645  *p++ = ' ';
646  }
647  }
648  else
649  {
650  *p++ = *q;
651  i++;
652  }
653  }
654  *p = '\0';
655 
657 
658  if (conv_buf != NULL)
659  {
661  free_and_init (conv_buf);
662  }
663 
664  return (CSQL_SUCCESS);
665 }
666 
667 /*
668  * csql_display_more_lines() - display lines in stdout.
669  * return: none
670  * title(in): optional title message
671  *
672  * Note: "\1" in line will be displayed `<' and `>', alternatively.
673  */
674 void
675 csql_display_more_lines (const char *title)
676 {
677  int i;
678  FILE *pf; /* pipe stream to pager */
679 #if !defined(WINDOWS)
680  void (*iq_pipe_save) (int sig);
681 
682  iq_pipe_save = signal (SIGPIPE, &iq_pipe_handler);
683 #endif /* ! WINDOWS */
684  if (setjmp (iq_Jmp_buf) == 0)
685  {
687 
688  /* display title */
689  if (title != NULL)
690  {
691  sprintf (csql_Scratch_text, "\n=== %s ===\n\n", title);
693  }
694 
695  for (i = 0; i < iq_Num_more_lines; i++)
696  {
697  csql_fputs (iq_More_lines[i], pf);
698  putc ('\n', pf);
699  }
700  putc ('\n', pf);
701 
703  }
704 #if !defined(WINDOWS)
705  signal (SIGPIPE, iq_pipe_save);
706 #endif /* ! WINDOWS */
707 }
708 
709 /*
710  * csql_free_more_lines() - free more lines built by csql_append_more_line()
711  * return: none
712  */
713 void
715 {
716  int i;
717 
718  if (iq_Num_more_lines > 0)
719  {
720  for (i = 0; i < iq_Num_more_lines; i++)
721  {
722  if (iq_More_lines[i] != NULL)
723  {
725  }
726  }
728  iq_Num_more_lines = 0;
729  }
730 }
731 
732 /*
733  * iq_pipe_handler() - Generic longjmp'ing signal handler used
734  * here we need to catch broken pipe
735  * return: none
736  * sig_no(in)
737  *
738  * Note:
739  */
740 static void
741 iq_pipe_handler (int sig_no)
742 {
743  longjmp (iq_Jmp_buf, 1);
744 }
745 
746 /*
747  * csql_check_server_down() - check if server is down
748  * return: none
749  *
750  * Note: If server is down, this function exit
751  */
752 void
754 {
756  {
758 
759  fprintf (csql_Error_fp, "Exiting ...\n");
760  csql_exit (EXIT_FAILURE);
761  }
762 }
763 
764 /*
765  * csql_get_tmp_buf()
766  * return: a pointer to a buffer for temporary formatting
767  * size(in): the number of characters required
768  *
769  * Note:
770  * This routine frees sprintf() users from having to worry
771  * too much about how much space they'll need; just call
772  * this with the number of characters required, and you'll
773  * get something that you don't have to worry about
774  * managing.
775  *
776  * Don't free the pointer you get back from this routine
777  */
778 char *
779 csql_get_tmp_buf (size_t size)
780 {
781  static char buf[1024];
782  static char *bufp = NULL;
783  static size_t bufsize = 0;
784 
785  if (size + 1 < sizeof (buf))
786  {
787  return buf;
788  }
789  else
790  {
791  /*
792  * buf isn't big enough, so see if we have an already-malloc'ed
793  * thing that is big enough. If so, use it; if not, free it if
794  * it exists, and then allocate a big enough one.
795  */
796  if (size + 1 < bufsize)
797  {
798  return bufp;
799  }
800  else
801  {
802  if (bufp)
803  {
804  free_and_init (bufp);
805  bufsize = 0;
806  }
807  bufsize = size + 1;
808  bufp = (char *) malloc (bufsize);
809  if (bufp == NULL)
810  {
812  bufsize = 0;
813  return NULL;
814  }
815  else
816  {
817  return bufp;
818  }
819  }
820  }
821 }
822 
823 /*
824  * nonscr_display_error() - format error message with global error code
825  * return: none
826  * buffer(out): message ouput buffer
827  * buf_length(in): size of output buffer
828  */
829 void
830 nonscr_display_error (char *buffer, int buf_length)
831 {
832  int remaining = buf_length;
833  char *msg;
834  const char *errmsg;
835  int len_errmsg;
836  char *con_buf_ptr = NULL;
837  int con_buf_size = 0;
838 
839  strncpy (buffer, "\n", remaining);
840  remaining -= strlen ("\n");
841 
843  strncat (buffer, msg, remaining);
844  remaining -= strlen (msg);
845 
846  errmsg = csql_errmsg (csql_Error_code);
847  len_errmsg = strlen (errmsg);
848 
850  && (*csql_text_utf8_to_console) (errmsg, len_errmsg, &con_buf_ptr, &con_buf_size) == NO_ERROR)
851  {
852  if (con_buf_ptr != NULL)
853  {
854  errmsg = con_buf_ptr;
855  len_errmsg = con_buf_size;
856  }
857  }
858 
859  if (len_errmsg > (remaining - 3) /* "\n\n" + NULL */ )
860  {
861  /* error msg will split into 2 pieces which is separated by "......" */
862  int print_len;
863  const char *separator = "......";
864  int separator_len = strlen (separator);
865 
866  print_len = (remaining - 3 - separator_len) / 2;
867  strncat (buffer, errmsg, print_len); /* first half */
868  strcat (buffer, separator);
869  strncat (buffer, errmsg + len_errmsg - print_len, print_len); /* second half */
870  remaining -= (print_len * 2 + separator_len);
871  }
872  else
873  {
874  strncat (buffer, errmsg, remaining);
875  remaining -= len_errmsg;
876  }
877 
878  if (con_buf_ptr != NULL)
879  {
880  free_and_init (con_buf_ptr);
881  }
882 
883  strncat (buffer, "\n\n", remaining);
884  remaining -= strlen ("\n\n");
885 
886  buffer[buf_length - 1] = '\0';
887  csql_fputs (buffer, csql_Error_fp);
888  logddl_set_err_msg (buffer);
889 }
890 
891 /*
892  * csql_edit_buffer_get_data() - get string of current editor contents
893  * return: pointer of contents
894  */
895 char *
897 {
898  if (csql_Edit_contents.data_size <= 0)
899  {
900  return ((char *) "");
901  }
902  return csql_Edit_contents.contents;
903 }
904 
905 static int
906 csql_edit_contents_expand (int required_size)
907 {
908  int new_alloc_size = csql_Edit_contents.alloc_size;
909  if (new_alloc_size >= required_size)
910  return CSQL_SUCCESS;
911 
912  if (new_alloc_size <= 0)
913  {
914  new_alloc_size = 1024;
915  }
916  while (new_alloc_size < required_size)
917  {
918  new_alloc_size *= 2;
919  }
920  csql_Edit_contents.contents = (char *) realloc (csql_Edit_contents.contents, new_alloc_size);
921  if (csql_Edit_contents.contents == NULL)
922  {
923  csql_Edit_contents.alloc_size = 0;
925  return CSQL_FAILURE;
926  }
927  csql_Edit_contents.alloc_size = new_alloc_size;
928  return CSQL_SUCCESS;
929 }
930 
931 /*
932  * csql_edit_buffer_append() - append string to current editor contents
933  * return: CSQL_SUCCESS/CSQL_FAILURE
934  * str(in): string to append
935  * flag_append_new_line(in): whether or not to append new line char
936  */
937 int
938 csql_edit_contents_append (const char *str, bool flag_append_new_line)
939 {
940  int str_len, new_data_size;
941  if (str == NULL)
942  {
943  return CSQL_SUCCESS;
944  }
945  str_len = strlen (str);
946  new_data_size = csql_Edit_contents.data_size + str_len;
947  if (csql_edit_contents_expand (new_data_size + 2) != CSQL_SUCCESS)
948  {
949  return CSQL_FAILURE;
950  }
951  memcpy (csql_Edit_contents.contents + csql_Edit_contents.data_size, str, str_len);
952  csql_Edit_contents.data_size = new_data_size;
953  if (flag_append_new_line)
954  {
955  csql_Edit_contents.contents[csql_Edit_contents.data_size++] = '\n';
956  }
957  csql_Edit_contents.contents[csql_Edit_contents.data_size] = '\0';
958  return CSQL_SUCCESS;
959 }
960 
961 /*
962  * csql_walk_statement () - parse str and change the state
963  * return : NULL
964  * str (in) : the new statement chunk received from input
965  */
966 void
967 csql_walk_statement (const char *str)
968 {
969  /* using flags but not adding many states in here may be not good choice, but it will not change the state machine
970  * model and save a lot of states. */
971  bool include_stmt = false;
972  bool is_last_stmt_valid = true;
973  const char *p;
974  int str_length;
975 
976  CSQL_STATEMENT_STATE state = csql_Edit_contents.state;
977 
978  if (str == NULL)
979  {
980  return;
981  }
982 
983  if (state == CSQL_STATE_CPP_COMMENT || state == CSQL_STATE_SQL_COMMENT)
984  {
985  /* these are single line comments and we're parsing a new line */
986  state = CSQL_STATE_GENERAL;
987  }
988 
989  if (state == CSQL_STATE_STATEMENT_END)
990  {
991  /* reset state in prev statement */
992  state = CSQL_STATE_GENERAL;
993  }
994 
995  str_length = strlen (str);
996  /* run as state machine */
997  for (p = str; p < str + str_length; p++)
998  {
999  switch (state)
1000  {
1001  case CSQL_STATE_GENERAL:
1002  switch (*p)
1003  {
1004  case '/':
1005  if (*(p + 1) == '/')
1006  {
1007  state = CSQL_STATE_CPP_COMMENT;
1008  p++;
1009  break;
1010  }
1011  if (*(p + 1) == '*')
1012  {
1013  state = CSQL_STATE_C_COMMENT;
1014  p++;
1015  break;
1016  }
1017  is_last_stmt_valid = true;
1018  break;
1019  case '-':
1020  if (*(p + 1) == '-')
1021  {
1022  state = CSQL_STATE_SQL_COMMENT;
1023  p++;
1024  break;
1025  }
1026  is_last_stmt_valid = true;
1027  break;
1028  case '\'':
1029  state = CSQL_STATE_SINGLE_QUOTE;
1030  is_last_stmt_valid = true;
1031  break;
1032  case '"':
1033  if (prm_get_bool_value (PRM_ID_ANSI_QUOTES) == false)
1034  {
1035  state = CSQL_STATE_MYSQL_QUOTE;
1036  }
1037  else
1038  {
1040  }
1041  is_last_stmt_valid = true;
1042  break;
1043  case '`':
1045  is_last_stmt_valid = true;
1046  break;
1047  case '[':
1049  is_last_stmt_valid = true;
1050  break;
1051  case ';':
1052  include_stmt = true;
1053  is_last_stmt_valid = false;
1054  if (*(p + 1) == 0)
1055  {
1056  state = CSQL_STATE_STATEMENT_END;
1057  }
1058  break;
1059  case ' ':
1060  case '\t':
1061  /* do not change is_last_stmt_valid */
1062  break;
1063  default:
1064  if (!is_last_stmt_valid)
1065  {
1066  is_last_stmt_valid = true;
1067  }
1068  break;
1069  }
1070  break;
1071 
1072  case CSQL_STATE_C_COMMENT:
1073  if (*p == '*' && *(p + 1) == '/')
1074  {
1075  state = CSQL_STATE_GENERAL;
1076  p++;
1077  break;
1078  }
1079  break;
1080 
1082  if (*p == '\n')
1083  {
1084  state = CSQL_STATE_GENERAL;
1085  }
1086  break;
1087 
1089  if (*p == '\n')
1090  {
1091  state = CSQL_STATE_GENERAL;
1092  }
1093  break;
1094 
1096  if (prm_get_bool_value (PRM_ID_NO_BACKSLASH_ESCAPES) == false && *p == '\\')
1097  {
1098  p++;
1099  }
1100  else if (*p == '\'')
1101  {
1102  if (*(p + 1) == '\'')
1103  {
1104  /* escape by '' */
1105  p++;
1106  }
1107  else
1108  {
1109  state = CSQL_STATE_GENERAL;
1110  }
1111  }
1112  break;
1113 
1115  if (prm_get_bool_value (PRM_ID_NO_BACKSLASH_ESCAPES) == false && *p == '\\')
1116  {
1117  p++;
1118  }
1119  else if (*p == '"')
1120  {
1121  if (*(p + 1) == '\"')
1122  {
1123  /* escape by "" */
1124  p++;
1125  }
1126  else
1127  {
1128  state = CSQL_STATE_GENERAL;
1129  }
1130  }
1131  break;
1132 
1134  if (*p == '"')
1135  {
1136  state = CSQL_STATE_GENERAL;
1137  }
1138  break;
1139 
1141  if (*p == '`')
1142  {
1143  state = CSQL_STATE_GENERAL;
1144  }
1145  break;
1146 
1148  if (*p == ']')
1149  {
1150  state = CSQL_STATE_GENERAL;
1151  }
1152  break;
1153 
1154  default:
1155  /* should not be here */
1156  break;
1157  }
1158  }
1159 
1160  /* when include other stmts and the last smt is non sense stmt. */
1161  if (include_stmt && !is_last_stmt_valid
1162  && (state == CSQL_STATE_SQL_COMMENT || state == CSQL_STATE_CPP_COMMENT || state == CSQL_STATE_GENERAL))
1163  {
1164  state = CSQL_STATE_STATEMENT_END;
1165  }
1166 
1167  csql_Edit_contents.state = state;
1168 }
1169 
1170 /*
1171  * csql_is_statement_complete () - check if end of statement is reached
1172  * return : true if statement end is reached, false otherwise
1173  */
1174 bool
1176 {
1177  if (csql_Edit_contents.state == CSQL_STATE_STATEMENT_END)
1178  {
1179  return true;
1180  }
1181  else
1182  {
1183  return false;
1184  }
1185 }
1186 
1187 /*
1188  * csql_is_statement_in_block () - check if statement state is string block or
1189  * comment block or identifier block
1190  * return : true if yes, false otherwise
1191  */
1192 bool
1194 {
1195  CSQL_STATEMENT_STATE state = csql_Edit_contents.state;
1196  if (state == CSQL_STATE_C_COMMENT || state == CSQL_STATE_SINGLE_QUOTE || state == CSQL_STATE_MYSQL_QUOTE
1198  || state == CSQL_STATE_BRACKET_IDENTIFIER)
1199  {
1200  return true;
1201  }
1202  else
1203  {
1204  return false;
1205  }
1206 }
1207 
1208 /*
1209  * csql_edit_buffer_clear() - clear current editor contents
1210  * return: none
1211  * NOTE: allocated memory in csql_Edit_contents is not freed.
1212  */
1213 void
1215 {
1216  csql_Edit_contents.data_size = 0;
1217  csql_Edit_contents.state = CSQL_STATE_GENERAL;
1218 }
1219 
1220 void
1222 {
1224  free_and_init (csql_Edit_contents.contents);
1225  csql_Edit_contents.alloc_size = 0;
1226 }
1227 
1228 /*
1229  * csql_edit_read_file() - read chars from the given file stream into
1230  * current editor contents
1231  * return: CSQL_FAILURE/CSQL_SUCCESS
1232  * fp(in): file stream
1233  */
1234 int
1236 {
1237  char line_buf[1024];
1238  bool is_first_read_line = true;
1239 
1240  while (fgets (line_buf, sizeof (line_buf), fp) != NULL)
1241  {
1242  char *line_begin = line_buf;
1243 
1244  if (is_first_read_line && intl_is_bom_magic (line_buf, strlen (line_buf)))
1245  {
1246  line_begin += 3;
1247  }
1248 
1249  is_first_read_line = false;
1250 
1251  if (csql_edit_contents_append (line_begin, false) != CSQL_SUCCESS)
1252  return CSQL_FAILURE;
1253  }
1254  return CSQL_SUCCESS;
1255 }
1256 
1257 /*
1258  * csql_edit_write_file() - write current editor contents to specified file
1259  * return: CSQL_FAILURE/CSQL_SUCCESS
1260  * fp(in): open file pointer
1261  */
1262 int
1264 {
1265  char *p = csql_Edit_contents.contents;
1266  int remain_size = csql_Edit_contents.data_size;
1267  int write_len;
1268  while (remain_size > 0)
1269  {
1270  write_len = (int) fwrite (p + (csql_Edit_contents.data_size - remain_size), 1, remain_size, fp);
1271  if (write_len <= 0)
1272  {
1274  return CSQL_FAILURE;
1275  }
1276  remain_size -= write_len;
1277  }
1278  return CSQL_SUCCESS;
1279 }
1280 
1281 typedef struct
1282 {
1284  int msg_id;
1286 
1301 };
1302 
1303 /*
1304  * csql_errmsg() - return an error message string according to the given
1305  * error code
1306  * return: error message
1307  * code(in): error code
1308  */
1309 const char *
1310 csql_errmsg (int code)
1311 {
1312  int msg_map_size;
1313  const char *msg;
1314 
1315  if (code == CSQL_ERR_OS_ERROR)
1316  {
1317  return (strerror (errno));
1318  }
1319  else if (code == CSQL_ERR_SQL_ERROR)
1320  {
1322  return ((msg == NULL) ? "" : msg);
1323  }
1324  else
1325  {
1326  int i;
1327 
1328  msg_map_size = DIM (csql_Err_msg_map);
1329  for (i = 0; i < msg_map_size; i++)
1330  {
1331  if (code == csql_Err_msg_map[i].error_code)
1332  {
1333  return (csql_get_message (csql_Err_msg_map[i].msg_id));
1334  }
1335  }
1337  }
1338 }
const char * csql_get_message(int message_index)
Definition: csql.c:2954
#define NO_ERROR
Definition: error_code.h:46
FILE * csql_Error_fp
Definition: csql.c:158
static int iq_Num_more_lines
Definition: csql_support.c:57
#define MSGCAT_CATALOG_CSQL
#define ER_FAILED
Definition: error_code.h:47
void csql_edit_contents_finalize()
const char * csql_errmsg(int code)
char * csql_edit_contents_get()
Definition: csql_support.c:896
void csql_display_csql_err(int line_no, int col_no)
Definition: csql_support.c:490
void csql_fputs(const char *str, FILE *fp)
Definition: csql_support.c:322
static CSQL_EDIT_CONTENTS csql_Edit_contents
Definition: csql_support.c:85
static jmp_buf iq_Jmp_buf
Definition: csql_support.c:58
static char ** iq_More_lines
Definition: csql_support.c:56
DB_SESSION_ERROR * db_get_next_error(DB_SESSION_ERROR *errors, int *line, int *col)
Definition: db_vdb.c:953
FILE * csql_popen(const char *cmd, FILE *fd)
Definition: csql_support.c:396
char * csql_get_tmp_buf(size_t size)
Definition: csql_support.c:779
void csql_check_server_down(void)
Definition: csql_support.c:753
bool csql_is_statement_complete(void)
#define SCRATCH_TEXT_LEN
Definition: csql.h:152
void nonscr_display_error(char *buffer, int buf_length)
Definition: csql_support.c:830
void logddl_set_err_msg(char *msg)
Definition: ddl_log.c:344
int csql_append_more_line(int indent, const char *line)
Definition: csql_support.c:550
int csql_edit_write_file(FILE *fp)
std::unique_ptr< FILE, file_closer > auto_close_file
Definition: filesys.hpp:43
#define assert(x)
bool csql_is_statement_in_block(void)
#define DEFAULT_DB_ERROR_MSG_LEVEL
Definition: csql_support.c:60
int db_error_code(void)
Definition: db_admin.c:2143
void csql_invoke_system(const char *command)
Definition: csql_support.c:226
void csql_walk_statement(const char *str)
Definition: csql_support.c:967
static int csql_get_user_home(char *homebuf, int bufsize)
Definition: csql_support.c:126
const char * db_error_string(int level)
Definition: db_admin.c:2116
#define TAB_STOP
Definition: csql_support.c:50
CSQL_STATEMENT_STATE state
Definition: csql_support.c:82
static int csql_edit_contents_expand(int required_size)
Definition: csql_support.c:906
enum csql_statement_state CSQL_STATEMENT_STATE
bool intl_is_bom_magic(const char *buf, const int size)
int csql_edit_contents_append(const char *str, bool flag_append_new_line)
Definition: csql_support.c:938
#define NULL
Definition: freelistheap.h:34
void csql_display_more_lines(const char *title)
Definition: csql_support.c:675
void csql_free_more_lines(void)
Definition: csql_support.c:714
static bool iq_output_device_is_a_tty(void)
Definition: csql_support.c:102
#define err(fd,...)
Definition: porting.h:431
#define MSGCAT_CSQL_SET_CSQL
Definition: csql.h:49
char csql_Scratch_text[SCRATCH_TEXT_LEN]
Definition: csql.c:146
static CSQL_ERR_MSG_MAP csql_Err_msg_map[]
void csql_display_session_err(DB_SESSION *session, int line_no)
Definition: csql_support.c:512
csql_statement_state
Definition: csql_support.c:62
void csql_fputs_console_conv(const char *str, FILE *fp)
Definition: csql_support.c:357
char csql_Pager_cmd[PATH_MAX]
Definition: csql.c:125
std::pair< std::string, FILE * > open_temp_file(const char *prefix, const char *mode="w", int flags=0)
int csql_invoke_system_editor(void)
Definition: csql_support.c:252
std::unique_ptr< const char, file_deleter > auto_delete_file
Definition: filesys.hpp:58
int(* csql_text_utf8_to_console)(const char *, const int, char **, int *)
Definition: csql.c:113
char * csql_get_real_path(const char *pathname)
Definition: csql_support.c:160
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define strlen(s1)
Definition: intl_support.c:43
void csql_exit(int exit_status)
Definition: csql.c:2691
bool prm_get_bool_value(PARAM_ID prm_id)
#define ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED
Definition: error_code.h:171
void csql_edit_contents_clear()
int i
Definition: dynamic_load.c:954
FILE * csql_Output_fp
Definition: csql.c:157
char * msgcat_message(int cat_id, int set_id, int msg_id)
static void iq_pipe_handler(int sig_no)
Definition: csql_support.c:741
static bool iq_input_device_is_a_tty(void)
Definition: csql_support.c:113
FILE * csql_Input_fp
Definition: csql.c:156
int csql_Error_code
Definition: csql.c:148
void csql_pclose(FILE *pf, FILE *fd)
Definition: csql_support.c:444
static void iq_format_err(char *string, int buf_size, int line_no, int col_no)
Definition: csql_support.c:462
char csql_Editor_cmd[PATH_MAX]
Definition: csql.c:129
DB_SESSION_ERROR * db_get_errors(DB_SESSION *session)
Definition: db_vdb.c:926
int csql_edit_read_file(FILE *fp)
const char ** p
Definition: dynamic_load.c:945
#define MORE_LINE_EXPANSION_UNIT
Definition: csql_support.c:53