CUBRID Engine  latest
parse_tree.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  * parse_tree.c -
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stddef.h>
28 #include <assert.h>
29 #include <setjmp.h>
30 #include <time.h>
31 #if !defined(WINDOWS)
32 #include <sys/time.h>
33 #endif
34 
35 #include "porting.h"
36 #include "dbi.h"
37 #include "parser.h"
38 #include "jansson.h"
39 #include "memory_alloc.h"
40 
41 #if defined(SERVER_MODE)
42 #include "connection_error.h"
43 #endif /* SERVER_MODE */
44 
45 #include "dbtype.h"
46 
47 #if defined (SUPPRESS_STRLEN_WARNING)
48 #define strlen(s1) ((int) strlen(s1))
49 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
50 
51 /*
52  * this should be big enough for "largish" select statements to print.
53  * It is sized at 8192 less enough to let it fit in 2 blocks with some
54  * overhead for malloc headers plus string block header.
55  */
56 #define STRINGS_PER_BLOCK (8192-(4*sizeof(long)+sizeof(char *)+40))
57 #define HASH_NUMBER 128
58 #define NODES_PER_BLOCK 256
59 
62 {
64  int parser_id;
66 };
67 
70 {
73  int parser_id;
74 };
75 
78 {
80  int parser_id;
83  int block_end;
84  union aligned
85  {
86  double dummy;
87  char chars[STRINGS_PER_BLOCK];
88  } u;
89 };
90 
91 /* Global reserved name table including info for each reserved name */
93 
94  /* record info attributes */
95  {"t_pageid", RESERVED_T_PAGEID, DB_TYPE_INTEGER}
96  ,
97  {"t_slotid", RESERVED_T_SLOTID, DB_TYPE_INTEGER}
98  ,
99  {"t_volumeid", RESERVED_T_VOLUMEID, DB_TYPE_INTEGER}
100  ,
101  {"t_offset", RESERVED_T_OFFSET, DB_TYPE_INTEGER}
102  ,
103  {"t_length", RESERVED_T_LENGTH, DB_TYPE_INTEGER}
104  ,
105  {"t_rectype", RESERVED_T_REC_TYPE, DB_TYPE_INTEGER}
106  ,
107  {"t_reprid", RESERVED_T_REPRID, DB_TYPE_INTEGER}
108  ,
109  {"t_chn", RESERVED_T_CHN, DB_TYPE_INTEGER}
110  ,
112  ,
113  {"t_delid", RESERVED_T_MVCC_DELID, DB_TYPE_BIGINT}
114  ,
115  {"t_flags", RESERVED_T_MVCC_FLAGS, DB_TYPE_INTEGER}
116  ,
117  {"t_prev_version", RESERVED_T_MVCC_PREV_VERSION_LSA, DB_TYPE_INTEGER}
118 
119  /* page header info attributes */
120  ,
121  {"p_class_oid", RESERVED_P_CLASS_OID, DB_TYPE_OBJECT}
122  ,
123  {"p_prev_pageid", RESERVED_P_PREV_PAGEID, DB_TYPE_INTEGER}
124  ,
125  {"p_next_pageid", RESERVED_P_NEXT_PAGEID, DB_TYPE_INTEGER}
126  ,
127  {"p_num_slots", RESERVED_P_NUM_SLOTS, DB_TYPE_INTEGER}
128  ,
129  {"p_num_records", RESERVED_P_NUM_RECORDS, DB_TYPE_INTEGER}
130  ,
131  {"p_anchor_type", RESERVED_P_ANCHOR_TYPE, DB_TYPE_INTEGER}
132  ,
133  {"p_alignment", RESERVED_P_ALIGNMENT, DB_TYPE_INTEGER}
134  ,
135  {"p_total_free", RESERVED_P_TOTAL_FREE, DB_TYPE_INTEGER}
136  ,
137  {"p_cont_free", RESERVED_P_CONT_FREE, DB_TYPE_INTEGER}
138  ,
139  {"p_offset_to_free_area", RESERVED_P_OFFSET_TO_FREE_AREA, DB_TYPE_INTEGER}
140  ,
141  {"p_is_saving", RESERVED_P_IS_SAVING, DB_TYPE_INTEGER}
142  ,
143  {"p_update_best", RESERVED_P_UPDATE_BEST, DB_TYPE_INTEGER}
144 
145  /* key info attributes */
146  ,
147  {"key_volumeid", RESERVED_KEY_VOLUMEID, DB_TYPE_INTEGER}
148  ,
149  {"key_pageid", RESERVED_KEY_PAGEID, DB_TYPE_INTEGER}
150  ,
151  {"key_slotid", RESERVED_KEY_SLOTID, DB_TYPE_INTEGER}
152  ,
153  {"key_key", RESERVED_KEY_KEY, DB_TYPE_NULL} /* Types should be determined at compilation */
154  ,
155  {"key_oid_count", RESERVED_KEY_OID_COUNT, DB_TYPE_INTEGER}
156  ,
157  {"key_first_oid", RESERVED_KEY_FIRST_OID, DB_TYPE_OBJECT}
158  ,
159  {"key_overflow_key", RESERVED_KEY_OVERFLOW_KEY, DB_TYPE_STRING}
160  ,
161  {"key_overflow_oids", RESERVED_KEY_OVERFLOW_OIDS, DB_TYPE_STRING}
162 
163  /* B-tree node info */
164  ,
165  {"bt_node_volumeid", RESERVED_BT_NODE_VOLUMEID, DB_TYPE_INTEGER}
166  ,
167  {"bt_node_pageid", RESERVED_BT_NODE_PAGEID, DB_TYPE_INTEGER}
168  ,
169  {"bt_node_type", RESERVED_BT_NODE_TYPE, DB_TYPE_STRING}
170  ,
171  {"bt_node_key_count", RESERVED_BT_NODE_KEY_COUNT, DB_TYPE_INTEGER}
172  ,
173  {"bt_node_first_key", RESERVED_BT_NODE_FIRST_KEY, DB_TYPE_NULL}
174  ,
175  {"bt_node_last_key", RESERVED_BT_NODE_LAST_KEY, DB_TYPE_NULL}
176 };
177 
178 #if defined(SERVER_MODE)
179 /* this is a kludge because many platforms do not handle extern
180  * linking per ANSI. This should be deleted when nodes get used in server.
181  */
182 static pthread_mutex_t blocks_lock = PTHREAD_MUTEX_INITIALIZER;
183 static pthread_mutex_t free_lists_lock = PTHREAD_MUTEX_INITIALIZER;
184 static pthread_mutex_t parser_memory_lock = PTHREAD_MUTEX_INITIALIZER;
185 static pthread_mutex_t parser_id_lock = PTHREAD_MUTEX_INITIALIZER;
186 #endif /* SERVER_MODE */
187 
191 
192 static int parser_id = 1;
193 
195 static void pt_free_node_blocks (const PARSER_CONTEXT * parser);
196 static PARSER_STRING_BLOCK *parser_create_string_block (const PARSER_CONTEXT * parser, const int length);
197 static void pt_free_a_string_block (const PARSER_CONTEXT * parser, PARSER_STRING_BLOCK * string_to_free);
198 static PARSER_STRING_BLOCK *pt_find_string_block (const PARSER_CONTEXT * parser, const char *old_string);
199 static char *pt_append_string_for (const PARSER_CONTEXT * parser, const char *old_string, const char *new_tail,
200  const int wrap_with_single_quote);
202  const char *new_tail, const int new_tail_length);
203 static int pt_register_parser (const PARSER_CONTEXT * parser);
204 static void pt_unregister_parser (const PARSER_CONTEXT * parser);
205 static void pt_free_string_blocks (const PARSER_CONTEXT * parser);
206 
207 /*
208  * pt_create_node_block () - creates a new block of nodes, links the block
209  * on the hash list for the parser, and returns the free list of new nodes
210  * return:
211  * parser(in):
212  */
213 static PT_NODE *
215 {
216  int idhash, inode;
217  PARSER_NODE_BLOCK *block;
218 #if defined(SERVER_MODE)
219  int rv;
220 #endif /* SERVER_MODE */
221 
222  block = (PARSER_NODE_BLOCK *) malloc (sizeof (PARSER_NODE_BLOCK));
223 
224  if (!block)
225  {
226  if (parser->jmp_env_active)
227  {
228  /* long jump back to routine that set up the jump env for clean up and run down. */
229  longjmp (((PARSER_CONTEXT *) parser)->jmp_env, 1);
230  }
231  else
232  {
234  return NULL;
235  }
236  }
237 
238  /* remember which parser allocated this block */
239  block->parser_id = parser->id;
240 
241  /* link blocks on the hash list for this id */
242  idhash = parser->id % HASH_NUMBER;
243 #if defined(SERVER_MODE)
244  rv = pthread_mutex_lock (&blocks_lock);
245 #endif /* SERVER_MODE */
246  block->next = parser_Node_blocks[idhash];
247  parser_Node_blocks[idhash] = block;
248 
249  /* link nodes for free list */
250  for (inode = 1; inode < NODES_PER_BLOCK; inode++)
251  {
252  block->nodes[inode - 1].next = &block->nodes[inode];
253  }
254  block->nodes[NODES_PER_BLOCK - 1].next = NULL;
255 
256 #if defined(SERVER_MODE)
257  pthread_mutex_unlock (&blocks_lock);
258 #endif /* SERVER_MODE */
259  /* return head of free list */
260  return &block->nodes[0];
261 }
262 
263 /*
264  * parser_create_node () - creates a new node for a given parser.
265  * First it tries the parser's free list. If empty it adds a new
266  * block of nodes to the free list
267  * return:
268  * parser(in):
269  */
270 PT_NODE *
272 {
273  int idhash;
274  PARSER_NODE_FREE_LIST *free_list;
275  PT_NODE *node;
276 #if defined(SERVER_MODE)
277  int rv;
278 #endif /* SERVER_MODE */
279 
280  /* find free list for for this id */
281  idhash = parser->id % HASH_NUMBER;
282 
283 #if defined(SERVER_MODE)
284  rv = pthread_mutex_lock (&free_lists_lock);
285 #endif /* SERVER_MODE */
286 
287  free_list = parser_Node_free_lists[idhash];
288  while (free_list != NULL && free_list->parser_id != parser->id)
289  {
290  free_list = free_list->next;
291  }
292 
293 #if defined(SERVER_MODE)
294  pthread_mutex_unlock (&free_lists_lock);
295 #endif /* SERVER_MODE */
296 
297  if (free_list == NULL)
298  {
299  /* this is an programming error ! The parser does not exist! */
300  return NULL;
301  }
302 
303  if (free_list->node == NULL)
304  {
305  /* do not need to use mutex : only used by one parser(and one thread) */
306  free_list->node = parser_create_node_block (parser);
307  if (free_list->node == NULL)
308  {
309  return NULL;
310  }
311  }
312 
313  node = free_list->node;
314  free_list->node = free_list->node->next;
315 
316  node->parser_id = parser->id; /* consistency check */
317 
318  return node;
319 }
320 
321 
322 /*
323  * pt_free_node_blocks () - frees all node blocks allocated to this parser
324  * return: none
325  * parser(in):
326  */
327 static void
329 {
330  int idhash;
331  PARSER_NODE_BLOCK *block;
332  PARSER_NODE_BLOCK **previous_block;
333 #if defined(SERVER_MODE)
334  int rv;
335 #endif /* SERVER_MODE */
336 
337  /* unlink blocks on the hash list for this id */
338  idhash = parser->id % HASH_NUMBER;
339 #if defined(SERVER_MODE)
340  rv = pthread_mutex_lock (&blocks_lock);
341 #endif /* SERVER_MODE */
342  previous_block = &parser_Node_blocks[idhash];
343  block = *previous_block;
344 
345  while (block != NULL)
346  {
347  if (block->parser_id == parser->id)
348  {
349  /* remove it from list, and free it */
350  *previous_block = block->next;
351  free_and_init (block);
352  }
353  else
354  {
355  /* keep it, and move to next block pointer */
356  previous_block = &block->next;
357  }
358  /* re-establish invariant */
359  block = *previous_block;
360  }
361 #if defined(SERVER_MODE)
362  pthread_mutex_unlock (&blocks_lock);
363 #endif /* SERVER_MODE */
364 }
365 
366 /*
367  * parser_create_string_block () - reates a new block of strings, links the block
368  * on the hash list for the parser, and returns the block
369  * return:
370  * parser(in):
371  * length(in):
372  */
373 static PARSER_STRING_BLOCK *
375 {
376  int idhash;
377  PARSER_STRING_BLOCK *block;
378 #if defined(SERVER_MODE)
379  int rv;
380 #endif /* SERVER_MODE */
381 
382  if (length < (int) STRINGS_PER_BLOCK)
383  {
384  block = (PARSER_STRING_BLOCK *) malloc (sizeof (PARSER_STRING_BLOCK));
385  if (!block)
386  {
387  if (parser->jmp_env_active)
388  {
389  /* long jump back to routine that set up the jump env for clean up and run down. */
390  longjmp (((PARSER_CONTEXT *) parser)->jmp_env, 1);
391  }
392  else
393  {
395  return NULL;
396  }
397  }
398  block->block_end = STRINGS_PER_BLOCK - 1;
399  }
400  else
401  {
402  /* This is an unusually large string. Allocate a special block for it, with space for one string, plus some space
403  * for appending to. */
404  block = (PARSER_STRING_BLOCK *) malloc (sizeof (PARSER_STRING_BLOCK) + (length + 1001 - STRINGS_PER_BLOCK));
405  if (!block)
406  {
407  if (parser->jmp_env_active)
408  {
409  /* long jump back to routine that set up the jump env for clean up and run down. */
410  longjmp (((PARSER_CONTEXT *) parser)->jmp_env, 1);
411  }
412  else
413  {
415  (sizeof (PARSER_STRING_BLOCK) + (length + 1001 - STRINGS_PER_BLOCK)));
416  return NULL;
417  }
418  }
419  block->block_end = CAST_BUFLEN (length + 1001 - 1);
420  }
421 
422  /* remember which parser allocated this block */
423  block->parser_id = parser->id;
424  block->last_string_start = -1;
425  block->last_string_end = -1;
426  block->u.chars[0] = 0;
427 
428  /* link blocks on the hash list for this id */
429  idhash = parser->id % HASH_NUMBER;
430 #if defined(SERVER_MODE)
431  rv = pthread_mutex_lock (&parser_memory_lock);
432 #endif /* SERVER_MODE */
433  block->next = parser_String_blocks[idhash];
434  parser_String_blocks[idhash] = block;
435 #if defined(SERVER_MODE)
436  pthread_mutex_unlock (&parser_memory_lock);
437 #endif /* SERVER_MODE */
438 
439  return block;
440 }
441 
442 
443 /*
444  * parser_allocate_string_buffer () - creates memory for a given parser
445  * return: allocated memory pointer
446  * parser(in):
447  * length(in):
448  * align(in):
449  *
450  * Note :
451  * First it tries to find length + 1 bytes in the parser's free strings list.
452  * If there is no room, it adds a new block of strings to the free
453  * strings list, at least large enough to hold new length plus
454  * 1 (for a null character). Thus, one can call it by
455  * copy_of_foo = pt_create_string(parser, strlen(foo));
456  */
457 void *
458 parser_allocate_string_buffer (const PARSER_CONTEXT * parser, const int length, const int align)
459 {
460  int idhash;
461  PARSER_STRING_BLOCK *block;
462 #if defined(SERVER_MODE)
463  int rv;
464 #endif /* SERVER_MODE */
465 
466 
467  /* find free string list for for this id */
468  idhash = parser->id % HASH_NUMBER;
469 #if defined(SERVER_MODE)
470  rv = pthread_mutex_lock (&parser_memory_lock);
471 #endif /* SERVER_MODE */
472  block = parser_String_blocks[idhash];
473  while (block != NULL
474  && (block->parser_id != parser->id
475  || ((block->block_end - block->last_string_end) < (length + (align - 1) + 1))))
476  {
477  block = block->next;
478  }
479 #if defined(SERVER_MODE)
480  pthread_mutex_unlock (&parser_memory_lock);
481 #endif /* SERVER_MODE */
482 
483  if (block == NULL)
484  {
485  block = parser_create_string_block (parser, length + (align - 1) + 1);
486  if (block == NULL)
487  {
488  return NULL;
489  }
490  }
491 
492  /* set start to the aligned length */
493  block->last_string_start = CAST_BUFLEN ((block->last_string_end + (align - 1) + 1) & ~(align - 1));
494  block->last_string_end = CAST_BUFLEN (block->last_string_start + length);
495  block->u.chars[block->last_string_start] = 0;
496 
497  return &block->u.chars[block->last_string_start];
498 }
499 
500 
501 /*
502  * pt_free_a_string_block() - finds a string block, removes it from
503  * the hash table linked list frees the memory
504  * return:
505  * parser(in):
506  * string_to_free(in):
507  */
508 static void
510 {
511  PARSER_STRING_BLOCK **previous_string;
512  PARSER_STRING_BLOCK *string;
513  int idhash;
514 #if defined(SERVER_MODE)
515  int rv;
516 #endif /* SERVER_MODE */
517 
518  /* find string holding old_string for for this parse_id */
519  idhash = parser->id % HASH_NUMBER;
520 #if defined(SERVER_MODE)
521  rv = pthread_mutex_lock (&parser_memory_lock);
522 #endif /* SERVER_MODE */
523  previous_string = &parser_String_blocks[idhash];
524  string = *previous_string;
525  while (string != string_to_free)
526  {
527  previous_string = &string->next;
528  string = *previous_string;
529  }
530 
531  if (string)
532  {
533  *previous_string = string->next;
534  free_and_init (string);
535  }
536 #if defined(SERVER_MODE)
537  pthread_mutex_unlock (&parser_memory_lock);
538 #endif /* SERVER_MODE */
539 }
540 
541 /*
542  * pt_find_string_block () - finds a string block from same parser that
543  * has oldstring as its last string
544  * return:
545  * parser(in):
546  * old_string(in):
547  */
548 static PARSER_STRING_BLOCK *
549 pt_find_string_block (const PARSER_CONTEXT * parser, const char *old_string)
550 {
551  PARSER_STRING_BLOCK *string;
552  int idhash;
553 #if defined(SERVER_MODE)
554  int rv;
555 #endif /* SERVER_MODE */
556 
557  /* find string holding old_string for for this parse_id */
558  idhash = parser->id % HASH_NUMBER;
559 #if defined(SERVER_MODE)
560  rv = pthread_mutex_lock (&parser_memory_lock);
561 #endif /* SERVER_MODE */
562  string = parser_String_blocks[idhash];
563  while (string != NULL
564  && (string->parser_id != parser->id || &(string->u.chars[string->last_string_start]) != old_string))
565  {
566  string = string->next;
567  }
568 #if defined(SERVER_MODE)
569  pthread_mutex_unlock (&parser_memory_lock);
570 #endif /* SERVER_MODE */
571 
572  return string;
573 }
574 
575 /*
576  * pt_append_string_for () - appends a tail to a string for a given parser
577  * return:
578  * parser(in):
579  * old_string(in/out):
580  * new_tail(in):
581  * wrap_with_single_quote(in):
582  *
583  * Note :
584  * The space allocated is at least their combined lengths plus one
585  * (for a null character). The two strings are logically concatenated
586  * and copied into the result string. The physical operation is typically
587  * more efficient, and conservative of memory.
588  * The given old_string is OVERWRITTEN.
589  */
590 static char *
591 pt_append_string_for (const PARSER_CONTEXT * parser, const char *old_string, const char *new_tail,
592  const int wrap_with_single_quote)
593 {
594  PARSER_STRING_BLOCK *string;
595  char *s;
596  int new_tail_length;
597 
598  /* here, you know you have two non-NULL pointers */
599  string = pt_find_string_block (parser, old_string);
600  new_tail_length = strlen (new_tail);
601  if (wrap_with_single_quote)
602  {
603  new_tail_length += 2; /* for opening/closing "'" */
604  }
605 
606  /* if we did not find old_string at the end of a string buffer, or if there is not room to concatenate the tail, copy
607  * both to new string */
608  if ((string == NULL) || ((string->block_end - string->last_string_end) < new_tail_length))
609  {
610  s = (char *) parser_allocate_string_buffer (parser, strlen (old_string) + new_tail_length, sizeof (char));
611  if (s == NULL)
612  {
613  return NULL;
614  }
615  strcpy (s, old_string);
616  if (wrap_with_single_quote)
617  {
618  strcat (s, "'");
619  }
620  strcat (s, new_tail);
621  if (wrap_with_single_quote)
622  {
623  strcat (s, "'");
624  }
625 
626  /* We might be appending to ever-growing buffers. Detect if there was a string found, but it was out of space,
627  * and it was the ONLY string in the buffer. If this happened, free it. */
628  if (string != NULL
629  /* && (already know there was not room, see above) */
630  && string->last_string_start == 0)
631  {
632  /* old_string is the only contents of string, free it. */
633  pt_free_a_string_block (parser, string);
634  }
635  }
636  else
637  {
638  /* found old_string at end of buffer with enough room concatenate new_tail in place when repeatedly adding to a
639  * buffer, eg. print buffer, this will grow the allocation efficiently to the needed size. */
640  s = &string->u.chars[string->last_string_end];
641  if (wrap_with_single_quote)
642  {
643  strcpy (s, "'");
644  strcpy (s + 1, new_tail);
645  strcpy (s + new_tail_length - 1, "'");
646  }
647  else
648  {
649  strcpy (s, new_tail);
650  }
651  string->last_string_end += new_tail_length;
652  s = &string->u.chars[string->last_string_start];
653  }
654 
655  return s;
656 }
657 
658 /*
659  * pt_append_bytes_for () - appends a tail to a old_string for a given parser
660  * return:
661  * parser(in):
662  * old_string(in/out):
663  * new_tail(in):
664  * new_tail_length(in):
665  *
666  * Note :
667  * The space allocated is at least their combined lengths plus one
668  * (for a null character) plus the size of a long. The two strings are
669  * logically concatenated and copied into the result string. The physical
670  * operation is typically more efficient, and conservative of memory.
671  * The given VARCHAR old_string is OVERWRITTEN.
672  *
673  * All VARCHAR strings for a parser will be freed by either parser_free_parser
674  * or parser_free_strings.
675  */
676 static PARSER_VARCHAR *
677 pt_append_bytes_for (const PARSER_CONTEXT * parser, PARSER_VARCHAR * old_string, const char *new_tail,
678  const int new_tail_length)
679 {
680  PARSER_STRING_BLOCK *string;
681  char *s;
682 
683  if (0 < parser->max_print_len && parser->max_print_len < old_string->length)
684  {
685  return old_string;
686  }
687 
688  /* here, you know you have two non-NULL pointers */
689  string = pt_find_string_block (parser, (char *) old_string);
690 
691  /* if we did not find old_string at the end of a string buffer, or if there is not room to concatenate the tail, copy
692  * both to new string */
693  if ((string == NULL) || ((string->block_end - string->last_string_end) < new_tail_length))
694  {
695  s = (char *) parser_allocate_string_buffer (parser,
696  offsetof (PARSER_VARCHAR,
697  bytes) + old_string->length + new_tail_length,
698  sizeof (long));
699  if (s == NULL)
700  {
701  return NULL;
702  }
703 
704  memcpy (s, old_string, old_string->length + offsetof (PARSER_VARCHAR, bytes));
705  old_string = (PARSER_VARCHAR *) s;
706  memcpy (&old_string->bytes[old_string->length], new_tail, new_tail_length);
707  old_string->length += (int) new_tail_length;
708  old_string->bytes[old_string->length] = 0; /* nul terminate */
709 
710  /* We might be appending to ever-growing buffers. Detect if there was a string found, but it was out of space,
711  * and it was the ONLY string in the buffer. If this happened, free it. */
712  if (string != NULL
713  /* && (already know there was not room, see above) */
714  && string->last_string_start == 0)
715  {
716  /* old_string is the only contents of string, free it. */
717  pt_free_a_string_block (parser, string);
718  }
719  }
720  else
721  {
722  /* found old_string at end of buffer with enough room concatenate new_tail in place when repeatedly adding to a
723  * buffer, eg. print buffer, this will grow the allocation efficiently to the needed size. */
724 
725  memcpy (&old_string->bytes[old_string->length], new_tail, new_tail_length);
726  old_string->length += (int) new_tail_length;
727  old_string->bytes[old_string->length] = 0; /* nul terminate */
728 
729  string->last_string_end += (int) new_tail_length;
730  s = &string->u.chars[string->last_string_start];
731  }
732 
733  return old_string;
734 }
735 
736 
737 /*
738  * pt_register_parser () - registers parser as existing by creating free list
739  * return: NO_ERROR on success, non-zero for ERROR
740  * parser(in):
741  */
742 static int
744 {
745  int idhash;
746  PARSER_NODE_FREE_LIST *free_list;
747 #if defined(SERVER_MODE)
748  int rv;
749 #endif /* SERVER_MODE */
750 
751  /* find free list for for this id */
752  idhash = parser->id % HASH_NUMBER;
753 #if defined(SERVER_MODE)
754  rv = pthread_mutex_lock (&free_lists_lock);
755 #endif /* SERVER_MODE */
756  free_list = parser_Node_free_lists[idhash];
757  while (free_list != NULL && free_list->parser_id != parser->id)
758  {
759  free_list = free_list->next;
760  }
761 
762  if (free_list == NULL)
763  {
764  /* this is the first time this parser allocated a node. */
765  /* set up a free list. This will only be done once per parser. */
766 
767  free_list = (PARSER_NODE_FREE_LIST *) calloc (sizeof (PARSER_NODE_FREE_LIST), 1);
768  if (free_list == NULL)
769  {
770 #if defined(SERVER_MODE)
771  pthread_mutex_unlock (&free_lists_lock);
772 #endif /* SERVER_MODE */
774  return ER_FAILED;
775  }
776  free_list->parser_id = parser->id;
777  free_list->next = parser_Node_free_lists[idhash];
778  parser_Node_free_lists[idhash] = free_list;
779  }
780  else
781  {
782 #if defined(SERVER_MODE)
783  pthread_mutex_unlock (&free_lists_lock);
784 #endif /* SERVER_MODE */
786  return ER_FAILED;
787  }
788 #if defined(SERVER_MODE)
789  pthread_mutex_unlock (&free_lists_lock);
790 #endif /* SERVER_MODE */
791  return NO_ERROR;
792 }
793 
794 /*
795  * pt_unregister_parser () - unregisters parser as existing,
796  * or registers it as not existing
797  * return: none
798  * parser(in):
799  */
800 static void
802 {
803  int idhash;
804  PARSER_NODE_FREE_LIST *free_list;
805  PARSER_NODE_FREE_LIST **previous_free_list;
806 #if defined(SERVER_MODE)
807  int rv;
808 #endif /* SERVER_MODE */
809 
810  /* find free list for for this id */
811  idhash = parser->id % HASH_NUMBER;
812 #if defined(SERVER_MODE)
813  rv = pthread_mutex_lock (&free_lists_lock);
814 #endif /* SERVER_MODE */
815  previous_free_list = &parser_Node_free_lists[idhash];
816  free_list = *previous_free_list;
817  while (free_list != NULL && free_list->parser_id != parser->id)
818  {
819  previous_free_list = &free_list->next;
820  free_list = *previous_free_list;
821  }
822 
823  if (free_list)
824  {
825  /* all is ok, remove the free list from the hash list of free lists. */
826  *previous_free_list = free_list->next;
827  free_and_init (free_list);
828  }
829 #if defined(SERVER_MODE)
830  pthread_mutex_unlock (&free_lists_lock);
831 #endif /* SERVER_MODE */
832 }
833 
834 void
836 {
837  /* before we free this node, see if we need to clear a db_value */
838  if (node->node_type == PT_VALUE && node->info.value.db_value_is_in_workspace)
839  {
841  }
843  {
845  }
846  if (node->node_type == PT_JSON_TABLE_COLUMN)
847  {
853  // db_values on_empty.m_default_value & on_error.m_default_value are allocated using area_alloc
854  }
855 }
856 
857 /*
858  * parser_free_node () - Return this node to this parser's node memory pool
859  * return:
860  * parser(in):
861  * node(in):
862  *
863  * Note :
864  * This only makes this memory eligible for re-use
865  * by the current parser. To return memory to virtual memory pool,
866  * pt_free_nodes or parser_free_parser should be called.
867  */
868 void
870 {
871  int idhash;
872  PARSER_NODE_FREE_LIST *free_list;
873 #if defined(SERVER_MODE)
874  int rv;
875 #endif /* SERVER_MODE */
876 
877  if (node == NULL)
878  {
879  assert_release (false);
880  return;
881  }
882 
884 
885  if (node->node_type == PT_SPEC)
886  {
887  /* prevent same spec_id on a parser tree */
888  return;
889  }
890 
891  /* find free list for for this id */
892  idhash = parser->id % HASH_NUMBER;
893 #if defined(SERVER_MODE)
894  rv = pthread_mutex_lock (&free_lists_lock);
895 #endif /* SERVER_MODE */
896  free_list = parser_Node_free_lists[idhash];
897  while (free_list != NULL && free_list->parser_id != parser->id)
898  {
899  free_list = free_list->next;
900  }
901 
902 #if defined(SERVER_MODE)
903  /* we can unlock mutex, since this free_list is only used by one parser */
904  pthread_mutex_unlock (&free_lists_lock);
905 #endif /* SERVER_MODE */
906 
907  if (free_list == NULL)
908  {
909  /* this is an programming error ! The parser does not exist! */
910  return;
911  }
912 
913  if (node->parser_id != parser->id)
914  {
915  /* this is an programming error ! The node is not from this parser. */
916  return;
917  }
918 
920  /*
921  * Always set the node type to maximum. This may
922  * keep us from doing bad things to the free list if we try to free
923  * this structure more than once. We shouldn't be doing that (i.e.,
924  * we should always be building trees, not graphs) but sometimes it
925  * does by accident, and if we don't watch for it we wind up with
926  * fatal errors. A common symptom is stack exhaustion during parser_free_tree
927  * as we try to recursively walk a cyclic free list.
928  */
930 
931  node->next = free_list->node;
932  free_list->node = node;
933 }
934 
935 
936 /*
937  * parser_alloc () - allocate memory for a given parser
938  * return:
939  * parser(in):
940  * length(in):
941  *
942  * Note :
943  * The space allocated is at least length plus 8.
944  * The space allocated is double word aligned ( a multiple of 8 ).
945  * Thus, one can call it by
946  * foo_buffer = parser_alloc (parser, strlen(foo));
947  * ALL BUFFERS for a parser will be FREED by either parser_free_parser
948  * or parser_free_strings.
949  */
950 void *
951 parser_alloc (const PARSER_CONTEXT * parser, const int length)
952 {
953 
954  void *pointer;
955 
956  pointer = parser_allocate_string_buffer (parser, length + sizeof (long), sizeof (double));
957  if (pointer)
958  memset (pointer, 0, length);
959 
960  return pointer;
961 }
962 
963 /*
964  * pt_append_string () - appends a tail to a string for a given parser
965  * return:
966  * parser(in):
967  * old_string(in/out):
968  * new_tail(in):
969  *
970  * Note :
971  * The space allocated is at least their combined lengths plus one
972  * (for a null character). The two strings are logically concatenated
973  * and copied into the result string. The physical operation is typically
974  * more efficient, and conservative of memory
975  *
976  * Note :
977  * pt_append_string won't modify old_string but it will return it to caller if new_tail is NULL.
978  */
979 char *
980 pt_append_string (const PARSER_CONTEXT * parser, const char *old_string, const char *new_tail)
981 {
982  char *s;
983 
984  if (new_tail == NULL)
985  {
986  s = CONST_CAST (char *, old_string); // it is up to caller
987  }
988  else if (old_string == NULL)
989  {
990  s = (char *) parser_allocate_string_buffer (parser, strlen (new_tail), sizeof (char));
991  if (s == NULL)
992  {
993  return NULL;
994  }
995  strcpy (s, new_tail);
996  }
997  else
998  {
999  s = pt_append_string_for (parser, old_string, new_tail, false);
1000  }
1001 
1002  return s;
1003 }
1004 
1005 /*
1006  * pt_append_bytes () - appends a byte tail to a string for a given parser
1007  * return:
1008  * parser(in):
1009  * old_string(in/out):
1010  * new_tail(in):
1011  * new_tail_length(in):
1012  */
1014 pt_append_bytes (const PARSER_CONTEXT * parser, PARSER_VARCHAR * old_string, const char *new_tail,
1015  const int new_tail_length)
1016 {
1017  PARSER_VARCHAR *s;
1018 
1019  if (old_string == NULL)
1020  {
1021  old_string =
1023  sizeof (long));
1024  if (old_string == NULL)
1025  {
1026  return NULL;
1027  }
1028  old_string->length = 0;
1029  old_string->bytes[0] = 0;
1030  }
1031 
1032  if (new_tail == NULL)
1033  {
1034  s = old_string;
1035  }
1036  else
1037  {
1038  s = pt_append_bytes_for ((PARSER_CONTEXT *) parser, old_string, new_tail, new_tail_length);
1039  }
1040 
1041  return s;
1042 }
1043 
1044 /*
1045  * pt_append_varchar () -
1046  * return:
1047  * parser(in):
1048  * old_string(in/out):
1049  * new_tail(in):
1050  */
1052 pt_append_varchar (const PARSER_CONTEXT * parser, PARSER_VARCHAR * old_string, const PARSER_VARCHAR * new_tail)
1053 {
1054  if (new_tail == NULL)
1055  {
1056  return old_string;
1057  }
1058 
1059  return pt_append_bytes (parser, old_string, (char *) new_tail->bytes, new_tail->length);
1060 }
1061 
1062 
1063 /*
1064  * pt_append_nulstring () - Append a nul terminated string to
1065  * a PARSER_VARCHAR binary string
1066  * return:
1067  * parser(in):
1068  * bstring(in):
1069  * nulstring(in):
1070  */
1072 pt_append_nulstring (const PARSER_CONTEXT * parser, PARSER_VARCHAR * bstring, const char *nulstring)
1073 {
1074  if (nulstring == NULL)
1075  {
1076  return bstring;
1077  }
1078 
1079  return pt_append_bytes (parser, bstring, nulstring, strlen (nulstring));
1080 }
1081 
1082 
1083 /*
1084  * pt_get_varchar_bytes () - return a PARSER_VARCHAR byte pointer
1085  * return:
1086  * string(in):
1087  */
1088 const unsigned char *
1090 {
1091  if (string != NULL)
1092  {
1093  return string->bytes;
1094  }
1095 
1096  return NULL;
1097 }
1098 
1099 
1100 /*
1101  * pt_get_varchar_length () - return a PARSER_VARCHAR length
1102  * return:
1103  * string(in):
1104  */
1105 int
1107 {
1108  if (string != NULL)
1109  {
1110  return string->length;
1111  }
1112 
1113  return 0;
1114 }
1115 
1116 
1117 /*
1118  * pt_free_string_blocks () - Return parser's string memory pool to virtual memory
1119  * return: none
1120  * parser(in):
1121  */
1122 static void
1124 {
1125  int idhash;
1126  PARSER_STRING_BLOCK *block;
1127  PARSER_STRING_BLOCK **previous_block;
1128 #if defined(SERVER_MODE)
1129  int rv;
1130 #endif /* SERVER_MODE */
1131 
1132  /* unlink blocks on the hash list for this id */
1133  idhash = parser->id % HASH_NUMBER;
1134 #if defined(SERVER_MODE)
1135  rv = pthread_mutex_lock (&parser_memory_lock);
1136 #endif /* SERVER_MODE */
1137  previous_block = &parser_String_blocks[idhash];
1138  block = *previous_block;
1139 
1140  while (block != NULL)
1141  {
1142  if (block->parser_id == parser->id)
1143  {
1144  /* remove it from list, and free it */
1145  *previous_block = block->next;
1146  free_and_init (block);
1147  }
1148  else
1149  {
1150  /* keep it, and move to next block pointer */
1151  previous_block = &block->next;
1152  }
1153  /* re-establish invariant */
1154  block = *previous_block;
1155  }
1156 #if defined(SERVER_MODE)
1157  pthread_mutex_unlock (&parser_memory_lock);
1158 #endif /* SERVER_MODE */
1159 }
1160 
1161 
1162 /*
1163  * parser_create_parser () - creates a parser context
1164  * The pointer can be passed to top level
1165  * parse functions and then freed by parser_free_parser.
1166  * return:
1167  */
1170 {
1172  struct timeval t;
1173 #if defined(SERVER_MODE)
1174  int rv;
1175 #endif /* SERVER_MODE */
1176  struct drand48_data rand_buf;
1177 
1178  parser = (PARSER_CONTEXT *) calloc (sizeof (PARSER_CONTEXT), 1);
1179  if (parser == NULL)
1180  {
1182  return NULL;
1183  }
1184 
1185 #if !defined (SERVER_MODE)
1187 #endif /* !SERVER_MODE */
1188 
1189 #if defined(SERVER_MODE)
1190  rv = pthread_mutex_lock (&parser_id_lock);
1191 #endif /* SERVER_MODE */
1192 
1193  parser->id = parser_id++;
1194 
1195 #if defined(SERVER_MODE)
1196  pthread_mutex_unlock (&parser_id_lock);
1197 #endif /* SERVER_MODE */
1198 
1199  if (pt_register_parser (parser) == ER_FAILED)
1200  {
1201  free_and_init (parser);
1202  return NULL;
1203  }
1204 
1205  parser->execution_values.row_count = -1;
1206 
1207  /* Generate random values for rand() and drand() */
1208  gettimeofday (&t, NULL);
1209  srand48_r (t.tv_usec, &rand_buf);
1210  lrand48_r (&rand_buf, &parser->lrand);
1211  drand48_r (&rand_buf, &parser->drand);
1212  db_make_null (&parser->sys_datetime);
1213  db_make_null (&parser->sys_epochtime);
1214 
1215  /* initialization */
1216  parser->query_id = NULL_QUERY_ID;
1217  parser->flag.is_in_and_list = 0;
1218  parser->flag.is_holdable = 0;
1219  parser->flag.is_xasl_pinned_reference = 0;
1220  parser->flag.recompile_xasl_pinned = 0;
1221  parser->auto_param_count = 0;
1222  parser->flag.return_generated_keys = 0;
1223  parser->flag.is_system_generated_stmt = 0;
1224  parser->flag.has_internal_error = 0;
1225  parser->max_print_len = 0;
1226  parser->flag.is_auto_commit = 0;
1227 
1228  return parser;
1229 }
1230 
1231 
1232 /*
1233  * parser_free_parser() - clean up all parse structures after they are through
1234  * being used. Values which need to be persistent, should have been
1235  * copied by now
1236  * return:
1237  * parser(in):
1238  */
1239 void
1241 {
1242  DB_VALUE *hv;
1243  int i;
1244 
1245  assert (parser != NULL);
1246 
1247  /* free string blocks */
1248  pt_free_string_blocks (parser);
1249  /* free node blocks */
1250  pt_free_node_blocks (parser);
1251  pt_unregister_parser (parser);
1252 
1253  if (parser->error_buffer)
1254  {
1255  free ((char *) parser->error_buffer);
1256  }
1257 
1258  if (parser->host_variables)
1259  {
1260  for (i = 0, hv = parser->host_variables; i < parser->host_var_count + parser->auto_param_count; i++, hv++)
1261  {
1262  db_value_clear (hv);
1263  }
1264  free_and_init (parser->host_variables);
1265  }
1266 
1267  if (parser->host_var_expected_domains)
1268  {
1270  }
1271 
1272  parser_free_lcks_classes (parser);
1273 
1274  /* free remaining plan trace string */
1275  if (parser->query_trace == true && parser->num_plan_trace > 0)
1276  {
1277  for (i = 0; i < parser->num_plan_trace; i++)
1278  {
1279  if (parser->plan_trace[i].format == QUERY_TRACE_TEXT)
1280  {
1281  if (parser->plan_trace[i].trace.text_plan != NULL)
1282  {
1283  free_and_init (parser->plan_trace[i].trace.text_plan);
1284  }
1285  }
1286  else if (parser->plan_trace[i].format == QUERY_TRACE_JSON)
1287  {
1288  if (parser->plan_trace[i].trace.json_plan != NULL)
1289  {
1290  json_object_clear (parser->plan_trace[i].trace.json_plan);
1291  json_decref (parser->plan_trace[i].trace.json_plan);
1292  parser->plan_trace[i].trace.json_plan = NULL;
1293  }
1294  }
1295  }
1296 
1297  parser->num_plan_trace = 0;
1298  }
1299 
1300  free_and_init (parser);
1301 }
1302 
1303 /*
1304  * parser_free_lcks_classes() - free allocated memory in pt_class_pre_fetch()
1305  * and pt_find_lck_classes ()
1306  * return: void
1307  * parser(in):
1308  */
1309 void
1311 {
1312  int i;
1313 
1314  if (parser->lcks_classes)
1315  {
1316  for (i = 0; i < parser->num_lcks_classes; i++)
1317  {
1318  free_and_init (parser->lcks_classes[i]);
1319  }
1320 
1321  free_and_init (parser->lcks_classes);
1322  parser->num_lcks_classes = 0;
1323  }
1324 
1325  return;
1326 }
1327 
1328 /*
1329  * pt_init_assignments_helper() - initialize enumeration of assignments
1330  * return: void
1331  * parser(in):
1332  * helper(in): address of assignments enumeration structure
1333  * assignment(in): assignments list to enumerate
1334  */
1335 void
1337 {
1338  helper->parser = parser;
1339  helper->assignment = assignment;
1340  helper->lhs = NULL;
1341  helper->rhs = NULL;
1342  helper->is_rhs_const = false;
1343  helper->is_n_column = false;
1344 }
1345 
1346 /*
1347  * pt_get_next_assignment() - get next assignment
1348  * return: returns left side of an assignment
1349  * ea(in/out): structure used in assignments enumeration.
1350  *
1351  * Note :
1352  * The function fills the ENUM_ASSIGNMENT structure with details related to
1353  * next assignment. In case there is a multiple assignment of form
1354  * (i1, i2, i3)=(select * from t) then the left side of assignment is split
1355  * and each element of it is returned as if there is a separate assignment and
1356  * the right side is always returned the same. In this case the is_n_columns
1357  * is set to true.
1358  */
1359 PT_NODE *
1361 {
1362  PT_NODE *lhs = ea->lhs, *rhs = NULL;
1363 
1364  ea->is_rhs_const = false;
1365  if (lhs != NULL)
1366  {
1367  if (lhs->next != NULL)
1368  {
1369  ea->is_n_column = true;
1370  ea->lhs = lhs->next;
1371  return ea->lhs;
1372  }
1373  ea->assignment = ea->assignment->next;
1374  }
1375 
1376  if (ea->assignment != NULL)
1377  {
1378  lhs = ea->assignment->info.expr.arg1;
1379  ea->rhs = rhs = ea->assignment->info.expr.arg2;
1381  if (lhs->node_type == PT_NAME)
1382  {
1383  ea->is_n_column = false;
1384  ea->lhs = lhs;
1385  return ea->lhs;
1386  }
1387  else
1388  { /* PT_IS_N_COLUMN_UPDATE_EXPR(lhs) == true */
1389  ea->is_n_column = true;
1390  ea->lhs = lhs->info.expr.arg1;
1391  return ea->lhs;
1392  }
1393  }
1394  else
1395  {
1396  ea->lhs = NULL;
1397  ea->rhs = NULL;
1398  ea->is_n_column = false;
1399  return NULL;
1400  }
1401 }
1402 
1403 /*
1404  * pt_count_assignments() - count assignments
1405  * return: the number of assignments in the assignments list
1406  * parser(in):
1407  * assignments(in): assignments to count.
1408  *
1409  * Note :
1410  * Multiple assignments are split and each component is counted.
1411  */
1412 int
1414 {
1416  int cnt = 0;
1417 
1418  pt_init_assignments_helper (parser, &ea, assignments);
1419 
1420  while (pt_get_next_assignment (&ea))
1421  {
1422  cnt++;
1423  }
1424 
1425  return cnt;
1426 }
1427 
1428 bool
1430 {
1431  if (type == PT_TYPE_MAYBE || type == PT_TYPE_NULL)
1432  {
1433  return true;
1434  }
1435 
1436  DB_TYPE converted_type = pt_type_enum_to_db (type);
1437 
1438  return db_is_json_value_type (converted_type);
1439 }
1440 
1441 bool
1443 {
1444  if (type == PT_TYPE_MAYBE || type == PT_TYPE_NULL)
1445  {
1446  return true;
1447  }
1448 
1449  DB_TYPE converted_type = pt_type_enum_to_db (type);
1450 
1451  return db_is_json_doc_type (converted_type);
1452 }
PT_NODE * next
Definition: parse_tree.h:3447
void parser_free_lcks_classes(PARSER_CONTEXT *parser)
Definition: parse_tree.c:1310
bool db_is_json_doc_type(DB_TYPE type)
Definition: db_macro.c:5066
static PARSER_NODE_FREE_LIST * parser_Node_free_lists[HASH_NUMBER]
Definition: parse_tree.c:189
static PARSER_STRING_BLOCK * parser_String_blocks[HASH_NUMBER]
Definition: parse_tree.c:190
#define NO_ERROR
Definition: error_code.h:46
char chars[STRINGS_PER_BLOCK]
Definition: parse_tree.c:87
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
void * parser_alloc(const PARSER_CONTEXT *parser, const int length)
Definition: parse_tree.c:951
struct db_value * m_default_value
PT_JSON_TABLE_COLUMN_INFO json_table_column_info
Definition: parse_tree.h:3314
static void pt_unregister_parser(const PARSER_CONTEXT *parser)
Definition: parse_tree.c:801
PARSER_VARCHAR * pt_append_nulstring(const PARSER_CONTEXT *parser, PARSER_VARCHAR *bstring, const char *nulstring)
Definition: parse_tree.c:1072
static PARSER_STRING_BLOCK * parser_create_string_block(const PARSER_CONTEXT *parser, const int length)
Definition: parse_tree.c:374
size_t align(size_t v)
Definition: align.h:19
DB_TYPE
Definition: dbtype_def.h:670
PT_RESERVED_NAME pt_Reserved_name_table[]
Definition: parse_tree.c:92
#define ER_FAILED
Definition: error_code.h:47
PARSER_NODE_FREE_LIST * next
Definition: parse_tree.c:71
PT_NODE nodes[NODES_PER_BLOCK]
Definition: parse_tree.c:65
struct json_table_column_behavior on_empty
Definition: parse_tree.h:3242
#define pthread_mutex_unlock(a)
Definition: area_alloc.c:51
QUERY_TRACE_FORMAT format
Definition: parse_tree.h:3519
enum pt_type_enum PT_TYPE_ENUM
Definition: parse_tree.h:962
#define assert_release(e)
Definition: error_manager.h:96
union pt_plan_trace_info::@133 trace
PT_EXPR_INFO expr
Definition: parse_tree.h:3299
PARSER_CONTEXT * parser_create_parser(void)
Definition: parse_tree.c:1169
bool pt_is_json_doc_type(PT_TYPE_ENUM type)
Definition: parse_tree.c:1442
PARSER_VARCHAR * pt_append_bytes(const PARSER_CONTEXT *parser, PARSER_VARCHAR *old_string, const char *new_tail, const int new_tail_length)
Definition: parse_tree.c:1014
static PARSER_STRING_BLOCK * pt_find_string_block(const PARSER_CONTEXT *parser, const char *old_string)
Definition: parse_tree.c:549
bool pt_is_json_value_type(PT_TYPE_ENUM type)
Definition: parse_tree.c:1429
bool db_is_json_value_type(DB_TYPE type)
Definition: db_macro.c:5043
char * error_buffer
Definition: parse_tree.h:3547
DB_VALUE * host_variables
Definition: parse_tree.h:3560
void parser_free_node_resources(PT_NODE *node)
Definition: parse_tree.c:835
void parser_free_parser(PARSER_CONTEXT *parser)
Definition: parse_tree.c:1240
DB_TYPE pt_type_enum_to_db(const PT_TYPE_ENUM t)
Definition: parse_dbi.c:2314
static void pt_free_string_blocks(const PARSER_CONTEXT *parser)
Definition: parse_tree.c:1123
unsigned char bytes[1]
Definition: parse_tree.h:3431
int pt_get_varchar_length(const PARSER_VARCHAR *string)
Definition: parse_tree.c:1106
#define NODES_PER_BLOCK
Definition: parse_tree.c:58
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
PT_NODE * arg2
Definition: parse_tree.h:2198
#define assert(x)
#define PT_IS_CONST_NOT_HOSTVAR(n)
Definition: parse_tree.h:370
PARSER_CONTEXT * parser
Definition: parse_tree.h:3632
static void pt_free_a_string_block(const PARSER_CONTEXT *parser, PARSER_STRING_BLOCK *string_to_free)
Definition: parse_tree.c:509
#define ER_GENERIC_ERROR
Definition: error_code.h:49
DB_VALUE db_value
Definition: parse_tree.h:3059
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
static PT_NODE * parser_create_node_block(const PARSER_CONTEXT *parser)
Definition: parse_tree.c:214
PARSER_NODE_BLOCK * next
Definition: parse_tree.c:63
struct json_table_column_behavior on_error
Definition: parse_tree.h:3241
int pt_count_assignments(PARSER_CONTEXT *parser, PT_NODE *assignments)
Definition: parse_tree.c:1413
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
PARSER_VARCHAR * pt_append_varchar(const PARSER_CONTEXT *parser, PARSER_VARCHAR *old_string, const PARSER_VARCHAR *new_tail)
Definition: parse_tree.c:1052
static int rv
Definition: area_alloc.c:52
SP_PARSER_CTX * parser
PT_NODE * arg1
Definition: parse_tree.h:2197
#define NULL
Definition: freelistheap.h:34
union parser_string_block::aligned u
char * pt_append_string(const PARSER_CONTEXT *parser, const char *old_string, const char *new_tail)
Definition: parse_tree.c:980
short db_value_is_in_workspace
Definition: parse_tree.h:3061
#define CONST_CAST(dest_type, expr)
Definition: porting.h:1060
PT_NODE * pt_get_next_assignment(PT_ASSIGNMENTS_HELPER *ea)
Definition: parse_tree.c:1360
static int pt_register_parser(const PARSER_CONTEXT *parser)
Definition: parse_tree.c:743
PT_NODE * parser_create_node(const PARSER_CONTEXT *parser)
Definition: parse_tree.c:271
TP_DOMAIN ** host_var_expected_domains
Definition: parse_tree.h:3561
static char * pt_append_string_for(const PARSER_CONTEXT *parser, const char *old_string, const char *new_tail, const int wrap_with_single_quote)
Definition: parse_tree.c:591
#define CAST_BUFLEN
Definition: porting.h:471
void parser_free_node(const PARSER_CONTEXT *parser, PT_NODE *node)
Definition: parse_tree.c:869
const unsigned char * pt_get_varchar_bytes(const PARSER_VARCHAR *string)
Definition: parse_tree.c:1089
#define HASH_NUMBER
Definition: parse_tree.c:57
#define ARG_FILE_LINE
Definition: error_manager.h:44
static void pt_free_node_blocks(const PARSER_CONTEXT *parser)
Definition: parse_tree.c:328
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define strlen(s1)
Definition: intl_support.c:43
void pt_init_assignments_helper(PARSER_CONTEXT *parser, PT_ASSIGNMENTS_HELPER *helper, PT_NODE *assignment)
Definition: parse_tree.c:1336
int i
Definition: dynamic_load.c:954
PT_VALUE_INFO value
Definition: parse_tree.h:3358
int db_make_null(DB_VALUE *value)
static PARSER_VARCHAR * pt_append_bytes_for(const PARSER_CONTEXT *parser, PARSER_VARCHAR *old_string, const char *new_tail, const int new_tail_length)
Definition: parse_tree.c:677
PT_PLAN_TRACE_INFO plan_trace[MAX_NUM_PLAN_TRACE]
Definition: parse_tree.h:3596
#define pthread_mutex_lock(a)
Definition: area_alloc.c:50
int db_value_clear(DB_VALUE *value)
Definition: db_macro.c:1588
PARSER_STRING_BLOCK * next
Definition: parse_tree.c:79
void * parser_allocate_string_buffer(const PARSER_CONTEXT *parser, const int length, const int align)
Definition: parse_tree.c:458
struct json_t * json_plan
Definition: parse_tree.h:3523
static PARSER_NODE_BLOCK * parser_Node_blocks[HASH_NUMBER]
Definition: parse_tree.c:188
char ** lcks_classes
Definition: parse_tree.h:3573
void parser_init_func_vectors(void)
PT_INSERT_VALUE_INFO insert_value
Definition: parse_tree.h:3310
#define STRINGS_PER_BLOCK
Definition: parse_tree.c:56