CUBRID Engine  latest
query_aggregate.cpp
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 // query_aggregate - implementation of aggregate functions execution during queries
21 //
22 
23 #include "query_aggregate.hpp"
24 
25 #include "arithmetic.h"
26 #include "btree.h" // btree_find_min_or_max_key, btree_get_unique_statistics_for_count
27 #include "db_json.hpp"
28 #include "dbtype.h"
29 #include "fetch.h"
30 #include "list_file.h"
31 #include "memory_alloc.h"
32 #include "memory_hash.h"
33 #include "object_domain.h"
34 #include "object_primitive.h"
35 #include "object_representation.h"
36 #include "query_opfunc.h"
37 #include "regu_var.hpp"
38 #include "string_opfunc.h"
39 #include "xasl.h" // QPROC_IS_INTERPOLATION_FUNC
40 #include "xasl_aggregate.hpp"
41 
42 #include <cmath>
43 
44 using namespace cubquery;
45 
46 //
47 // static functions declarations
48 //
50  cubxasl::aggregate_accumulator_domain *domain, FUNC_TYPE func_type,
51  tp_domain *func_domain, db_value *value, bool is_acc_to_acc);
54  cubxasl::aggregate_accumulator_domain *domain,
55  FUNC_TYPE func_type, tp_domain *func_domain,
56  std::vector<DB_VALUE> &db_values);
58  QUERY_ID query_id);
61  VAL_DESCR *val_desc_p);
64  QFILE_LIST_SCAN_ID *scan_id);
65 
66 static int qdata_group_concat_first_value (THREAD_ENTRY *thread_p, AGGREGATE_TYPE *agg_p, DB_VALUE *dbvalue);
67 static int qdata_group_concat_value (THREAD_ENTRY *thread_p, AGGREGATE_TYPE *agg_p, DB_VALUE *dbvalue);
68 
69 //
70 // implementation
71 //
72 
73 static int
75 {
77  QFILE_LIST_ID *list_id_p;
78  int ls_flag = QFILE_FLAG_DISTINCT;
79 
80  /* since max(distinct a) == max(a), handle these without distinct processing */
81  if (agg_p->function == PT_MAX || agg_p->function == PT_MIN)
82  {
83  agg_p->option = Q_ALL;
84  return NO_ERROR;
85  }
86 
87  type_list.type_cnt = 1;
88  type_list.domp = (TP_DOMAIN **) db_private_alloc (thread_p, sizeof (TP_DOMAIN *));
89 
90  if (type_list.domp == NULL)
91  {
92  return ER_FAILED;
93  }
94 
95  type_list.domp[0] = agg_p->operands->value.domain;
96  /* if the agg has ORDER BY force setting 'QFILE_FLAG_ALL' : in this case, no additional SORT_LIST will be created,
97  * but the one in the aggregate_list_node structure will be used */
98  if (agg_p->sort_list != NULL)
99  {
100  ls_flag = QFILE_FLAG_ALL;
101  }
102  list_id_p = qfile_open_list (thread_p, &type_list, NULL, query_id, ls_flag);
103 
104  if (list_id_p == NULL)
105  {
106  db_private_free_and_init (thread_p, type_list.domp);
107  return ER_FAILED;
108  }
109 
110  db_private_free_and_init (thread_p, type_list.domp);
111 
112  qfile_close_list (thread_p, agg_p->list_id);
113  qfile_destroy_list (thread_p, agg_p->list_id);
114 
115  if (qfile_copy_list_id (agg_p->list_id, list_id_p, true) != NO_ERROR)
116  {
117  QFILE_FREE_AND_INIT_LIST_ID (list_id_p);
118  return ER_FAILED;
119  }
120 
121  QFILE_FREE_AND_INIT_LIST_ID (list_id_p);
122 
123  return NO_ERROR;
124 }
125 
126 /*
127  * qdata_initialize_aggregate_list () -
128  * return: NO_ERROR, or ER_code
129  * agg_list(in) : Aggregate expression node list
130  * query_id(in) : Associated query id
131  *
132  * Note: Initialize the aggregate expression list.
133  */
134 int
136  QUERY_ID query_id)
137 {
139 
140  for (agg_p = agg_list_p; agg_p != NULL; agg_p = agg_p->next)
141  {
142 
143  /* the value of groupby_num() remains unchanged; it will be changed while evaluating groupby_num predicates
144  * against each group at 'xs_eval_grbynum_pred()' */
145  if (agg_p->function == PT_GROUPBY_NUM)
146  {
147  /* nothing to do with groupby_num() */
148  continue;
149  }
150 
151  /* CAUTION : if modify initializing ACC's value then should change qdata_alloc_agg_hvalue() */
152  agg_p->accumulator.curr_cnt = 0;
155  {
156  return ER_FAILED;
157  }
158 
159  /* This set is made, because if class is empty, aggregate results should return NULL, except count(*) and count */
160  if (agg_p->function == PT_COUNT_STAR || agg_p->function == PT_COUNT)
161  {
162  db_make_int (agg_p->accumulator.value, 0);
163  }
164 
165  /* create temporary list file to handle distincts */
166  if (agg_p->option == Q_DISTINCT || agg_p->sort_list != NULL)
167  {
168  /* NOTE: cume_dist and percent_rank do NOT need sorting */
169  if (agg_p->function != PT_CUME_DIST && agg_p->function != PT_PERCENT_RANK)
170  {
171  if (qdata_process_distinct_or_sort (thread_p, agg_p, query_id) != NO_ERROR)
172  {
173  return ER_FAILED;
174  }
175  }
176  }
177 
178  if (agg_p->function == PT_CUME_DIST || agg_p->function == PT_PERCENT_RANK)
179  {
180  /* init info.dist_percent */
181  agg_p->info.dist_percent.const_array = NULL;
182  agg_p->info.dist_percent.list_len = 0;
183  agg_p->info.dist_percent.nlargers = 0;
184  }
185  else
186  {
187  /* If there are other functions need initializing. Do it here. */
188  ;
189  }
190  }
191 
192  return NO_ERROR;
193 }
194 
195 /*
196  * qdata_aggregate_accumulator_to_accumulator () - aggregate two accumulators
197  * return: error code or NO_ERROR
198  * thread_p(in): thread
199  * acc(in/out): source1 and target accumulator
200  * acc_dom(in): accumulator domain
201  * func_type(in): function
202  * func_domain(in): function domain
203  * new_acc(in): source2 accumulator
204  */
205 int
207  cubxasl::aggregate_accumulator_domain *acc_dom, FUNC_TYPE func_type,
208  tp_domain *func_domain, cubxasl::aggregate_accumulator *new_acc)
209 {
210  TP_DOMAIN *double_domain;
211  int error = NO_ERROR;
212 
213  switch (func_type)
214  {
215  case PT_GROUPBY_NUM:
216  case PT_COUNT_STAR:
217  /* do nothing */
218  break;
219 
220  case PT_MIN:
221  case PT_MAX:
222  case PT_COUNT:
223  case PT_AGG_BIT_AND:
224  case PT_AGG_BIT_OR:
225  case PT_AGG_BIT_XOR:
226  case PT_AVG:
227  case PT_SUM:
228  // these functions only affect acc.value and new_acc can be treated as an ordinary value
229  error = qdata_aggregate_value_to_accumulator (thread_p, acc, acc_dom, func_type, func_domain, new_acc->value, true);
230  break;
231 
232  // for these two situations we just need to merge
233  case PT_JSON_ARRAYAGG:
234  case PT_JSON_OBJECTAGG:
235  error = db_evaluate_json_merge_preserve (new_acc->value, &acc->value, 1);
236  break;
237 
238  case PT_STDDEV:
239  case PT_STDDEV_POP:
240  case PT_STDDEV_SAMP:
241  case PT_VARIANCE:
242  case PT_VAR_POP:
243  case PT_VAR_SAMP:
244  /* we don't copy operator; default domain is double */
245  double_domain = tp_domain_resolve_default (DB_TYPE_DOUBLE);
246 
247  if (acc->curr_cnt < 1 && new_acc->curr_cnt >= 1)
248  {
249  /* initialize domains */
251  {
252  return ER_FAILED;
253  }
255  {
256  return ER_FAILED;
257  }
258 
259  /* clear values */
260  pr_clear_value (acc->value);
261  pr_clear_value (acc->value2);
262 
263  /* set values */
264  double_domain->type->setval (acc->value, new_acc->value, true);
265  double_domain->type->setval (acc->value2, new_acc->value2, true);
266  }
267  else if (acc->curr_cnt >= 1 && new_acc->curr_cnt >= 1)
268  {
269  /* acc.value += new_acc.value */
270  if (qdata_add_dbval (acc->value, new_acc->value, acc->value, double_domain) != NO_ERROR)
271  {
272  return ER_FAILED;
273  }
274 
275  /* acc.value2 += new_acc.value2 */
276  if (qdata_add_dbval (acc->value2, new_acc->value2, acc->value2, double_domain) != NO_ERROR)
277  {
278  return ER_FAILED;
279  }
280  }
281  else
282  {
283  /* we don't treat cases when new_acc or both accumulators are uninitialized */
284  }
285  break;
286 
287  default:
289  return ER_FAILED;
290  }
291 
292  /* increase tuple count */
293  acc->curr_cnt += new_acc->curr_cnt;
294 
295  /* all ok */
296  return error;
297 }
298 
299 /*
300  * qdata_aggregate_value_to_accumulator () - aggregate a value to accumulator
301  * returns: error code or NO_ERROR
302  * thread_p(in): thread
303  * acc(in): accumulator
304  * domain(in): accumulator domain
305  * func_type(in): function type
306  * func_domain(in): function domain
307  * value(in): value
308  * value_next(int): value of the second argument; used only for JSON_OBJECTAGG
309  */
310 static int
312  cubxasl::aggregate_accumulator_domain *domain, FUNC_TYPE func_type,
313  tp_domain *func_domain, db_value *value, bool is_acc_to_acc)
314 {
315  DB_VALUE squared;
316  bool copy_operator = false;
317  int coll_id = -1;
318 
319  if (DB_IS_NULL (value))
320  {
321  return NO_ERROR;
322  }
323 
324  if (domain != NULL && domain->value_dom != NULL)
325  {
326  coll_id = domain->value_dom->collation_id;
327  }
328 
329  /* aggregate new value */
330  switch (func_type)
331  {
332  case PT_MIN:
333  if (coll_id == -1)
334  {
335  return ER_FAILED;
336  }
337  if (acc->curr_cnt < 1 || domain->value_dom->type->cmpval (acc->value, value, 1, 1, NULL, coll_id) > 0)
338  {
339  /* we have new minimum */
340  copy_operator = true;
341  }
342  break;
343 
344  case PT_MAX:
345  if (coll_id == -1)
346  {
347  return ER_FAILED;
348  }
349  if (acc->curr_cnt < 1 || domain->value_dom->type->cmpval (acc->value, value, 1, 1, NULL, coll_id) < 0)
350  {
351  /* we have new maximum */
352  copy_operator = true;
353  }
354  break;
355 
356  case PT_COUNT:
357  if (is_acc_to_acc)
358  {
359  /* from qdata_aggregate_accumulator_to_accumulator (). value param is number of count */
360  db_make_int (acc->value, db_get_int (acc->value) + db_get_int (value));
361  }
362  else
363  {
364  /* from qdata_aggregate_multiple_values_to_accumulator(). value param is value of column */
365  if (acc->curr_cnt < 1)
366  {
367  /* first value */
368  db_make_int (acc->value, 1);
369  }
370  else
371  {
372  /* increment */
373  db_make_int (acc->value, db_get_int (acc->value) + 1);
374  }
375  }
376  break;
377 
378  case PT_AGG_BIT_AND:
379  case PT_AGG_BIT_OR:
380  case PT_AGG_BIT_XOR:
381  {
382  int error;
383  DB_VALUE tmp_val;
384  db_make_bigint (&tmp_val, (DB_BIGINT) 0);
385 
386  if (acc->curr_cnt < 1)
387  {
388  /* init result value */
389  if (!DB_IS_NULL (value))
390  {
391  if (qdata_bit_or_dbval (&tmp_val, value, acc->value, domain->value_dom) != NO_ERROR)
392  {
393  return ER_FAILED;
394  }
395  }
396  }
397  else
398  {
399  /* update result value */
400  if (!DB_IS_NULL (value))
401  {
402  if (DB_IS_NULL (acc->value))
403  {
404  /* basically an initialization */
405  if (qdata_bit_or_dbval (&tmp_val, value, acc->value, domain->value_dom) != NO_ERROR)
406  {
407  return ER_FAILED;
408  }
409  }
410  else
411  {
412  /* actual computation */
413  if (func_type == PT_AGG_BIT_AND)
414  {
415  error = qdata_bit_and_dbval (acc->value, value, acc->value, domain->value_dom);
416  }
417  else if (func_type == PT_AGG_BIT_OR)
418  {
419  error = qdata_bit_or_dbval (acc->value, value, acc->value, domain->value_dom);
420  }
421  else
422  {
423  error = qdata_bit_xor_dbval (acc->value, value, acc->value, domain->value_dom);
424  }
425 
426  if (error != NO_ERROR)
427  {
428  return ER_FAILED;
429  }
430  }
431  }
432  }
433  }
434  break;
435 
436  case PT_AVG:
437  case PT_SUM:
438  if (acc->curr_cnt < 1)
439  {
440  copy_operator = true;
441  }
442  else
443  {
444  /* values are added up in acc.value */
445  if (qdata_add_dbval (acc->value, value, acc->value, domain->value_dom) != NO_ERROR)
446  {
447  return ER_FAILED;
448  }
449  }
450  break;
451 
452  case PT_STDDEV:
453  case PT_STDDEV_POP:
454  case PT_STDDEV_SAMP:
455  case PT_VARIANCE:
456  case PT_VAR_POP:
457  case PT_VAR_SAMP:
458  /* coerce value to DOUBLE domain */
459  if (tp_value_coerce (value, value, domain->value_dom) != DOMAIN_COMPATIBLE)
460  {
461  return ER_FAILED;
462  }
463 
464  if (acc->curr_cnt < 1)
465  {
466  /* calculate X^2 */
467  if (qdata_multiply_dbval (value, value, &squared, domain->value2_dom) != NO_ERROR)
468  {
469  return ER_FAILED;
470  }
471 
472  /* clear values */
473  pr_clear_value (acc->value);
474  pr_clear_value (acc->value2);
475 
476  /* set values */
477  domain->value_dom->type->setval (acc->value, value, true);
478  domain->value2_dom->type->setval (acc->value2, &squared, true);
479  }
480  else
481  {
482  /* compute X^2 */
483  if (qdata_multiply_dbval (value, value, &squared, domain->value2_dom) != NO_ERROR)
484  {
485  return ER_FAILED;
486  }
487 
488  /* acc.value += X */
489  if (qdata_add_dbval (acc->value, value, acc->value, domain->value_dom) != NO_ERROR)
490  {
491  pr_clear_value (&squared);
492  return ER_FAILED;
493  }
494 
495  /* acc.value += X^2 */
496  if (qdata_add_dbval (acc->value2, &squared, acc->value2, domain->value2_dom) != NO_ERROR)
497  {
498  pr_clear_value (&squared);
499  return ER_FAILED;
500  }
501 
502  /* done with squared */
503  pr_clear_value (&squared);
504  }
505  break;
506 
507  case PT_JSON_ARRAYAGG:
508  if (db_accumulate_json_arrayagg (value, acc->value) != NO_ERROR)
509  {
510  return ER_FAILED;
511  }
512  break;
513 
514  default:
516  return ER_FAILED;
517  }
518 
519  /* copy operator if necessary */
520  if (copy_operator)
521  {
522  DB_TYPE type = DB_VALUE_DOMAIN_TYPE (value);
523  pr_clear_value (acc->value);
524 
525  if (TP_DOMAIN_TYPE (domain->value_dom) != type)
526  {
527  int coerce_error = db_value_coerce (value, acc->value, domain->value_dom);
528  if (coerce_error != NO_ERROR)
529  {
530  /* set error here */
531  return ER_FAILED;
532  }
533  }
534  else
535  {
536  pr_clone_value (value, acc->value);
537  }
538  }
539 
540  /* clear value and exit nicely */
541  return NO_ERROR;
542 }
543 
544 static int
546  cubxasl::aggregate_accumulator_domain *domain, FUNC_TYPE func_type,
547  tp_domain *func_domain, std::vector<DB_VALUE> &db_values)
548 {
549  // we have only one argument so aggregate only the first db_value
550  if (db_values.size () == 1)
551  {
552  return qdata_aggregate_value_to_accumulator (thread_p, acc, domain, func_type, func_domain, &db_values[0], false);
553  }
554 
555  // maybe this condition will be changed in the future based on the future arguments conditions
556  for (DB_VALUE &db_value : db_values)
557  {
558  if (DB_IS_NULL (&db_value))
559  {
560  return NO_ERROR;
561  }
562  }
563 
564  switch (func_type)
565  {
566  case PT_JSON_OBJECTAGG:
567  if (db_accumulate_json_objectagg (&db_values[0], &db_values[1], acc->value) != NO_ERROR)
568  {
569  return ER_FAILED;
570  }
571  break;
572 
573  default:
575  return ER_FAILED;
576  }
577 
578  return NO_ERROR;
579 }
580 
581 /*
582  * qdata_evaluate_aggregate_list () -
583  * return: NO_ERROR, or ER_code
584  * agg_list(in): aggregate expression node list
585  * val_desc_p(in): value descriptor
586  * alt_acc_list(in): alternate accumulator list
587  *
588  * Note: Evaluate given aggregate expression list.
589  * Note2: If alt_acc_list is not provided, default accumulators will be used.
590  * Alternate accumulators can not be used for DISTINCT processing or
591  * the GROUP_CONCAT and MEDIAN function.
592  */
593 int
595  val_descr *val_desc_p, cubxasl::aggregate_accumulator *alt_acc_list)
596 {
598  cubxasl::aggregate_accumulator *accumulator;
599  DB_VALUE *percentile_val = NULL;
600  PR_TYPE *pr_type_p;
601  DB_TYPE dbval_type;
602  OR_BUF buf;
603  char *disk_repr_p = NULL;
604  int dbval_size, i, error;
606  DB_VALUE *db_value_p = NULL;
607 
608  for (agg_p = agg_list_p, i = 0; agg_p != NULL; agg_p = agg_p->next, i++)
609  {
610  std::vector<DB_VALUE> db_values;
611 
612  /* determine accumulator */
613  accumulator = (alt_acc_list != NULL ? &alt_acc_list[i] : &agg_p->accumulator);
614 
615  if (agg_p->flag_agg_optimize)
616  {
617  continue;
618  }
619 
620  if (agg_p->function == PT_COUNT_STAR)
621  {
622  /* increment and continue */
623  accumulator->curr_cnt++;
624  continue;
625  }
626 
627  /*
628  * the value of groupby_num() remains unchanged;
629  * it will be changed while evaluating groupby_num predicates
630  * against each group at 'xs_eval_grbynum_pred()'
631  */
632  if (agg_p->function == PT_GROUPBY_NUM)
633  {
634  /* nothing to do with groupby_num() */
635  continue;
636  }
637 
638  if (agg_p->function == PT_CUME_DIST || agg_p->function == PT_PERCENT_RANK)
639  {
640  /* CUME_DIST and PERCENT_RANK use a REGU_VAR_LIST reguvar as operator and are treated in a special manner */
641  error = qdata_calculate_aggregate_cume_dist_percent_rank (thread_p, agg_p, val_desc_p);
642  if (error != NO_ERROR)
643  {
644  return error;
645  }
646 
647  continue;
648  }
649 
650  /* fetch operands value. aggregate regulator variable should only contain constants */
651  REGU_VARIABLE_LIST operand = NULL;
652  for (operand = agg_p->operands; operand != NULL; operand = operand->next)
653  {
654  // create an empty value
655  db_values.emplace_back ();
656 
657  // fetch it
658  if (fetch_copy_dbval (thread_p, &operand->value, val_desc_p, NULL, NULL, NULL,
659  &db_values.back ()) != NO_ERROR)
660  {
661  pr_clear_value_vector (db_values);
662  return ER_FAILED;
663  }
664  }
665 
666  /*
667  * eliminate null values
668  * consider only the first argument, because for the rest will depend on the function
669  */
670  db_value_p = &db_values[0];
671  if (DB_IS_NULL (db_value_p))
672  {
673  /*
674  * for JSON_ARRAYAGG we need to include also NULL values in the result set
675  * so we need to construct a NULL JSON value
676  */
677  if (agg_p->function == PT_JSON_ARRAYAGG)
678  {
679  // this creates a new JSON_DOC with the type DB_JSON_NULL
680  db_make_json (db_value_p, db_json_allocate_doc (), true);
681  }
682  /*
683  * for JSON_OBJECTAGG we need to include keep track of key-value pairs
684  * the key can not be NULL so this will throw an error
685  * the value can be NULL and we will wrap this into a JSON with DB_JSON_NULL type in the next statement
686  */
687  else if (agg_p->function == PT_JSON_OBJECTAGG)
688  {
689  pr_clear_value_vector (db_values);
692  }
693  else
694  {
695  pr_clear_value_vector (db_values);
696  continue;
697  }
698  }
699 
700  /*
701  * for JSON_OBJECTAGG, we wrap the second argument with a null JSON only if the value is NULL
702  */
703  if (agg_p->function == PT_JSON_OBJECTAGG)
704  {
705  if (DB_IS_NULL (&db_values[1]))
706  {
707  db_make_json (&db_values[1], db_json_allocate_doc (), true);
708  }
709  }
710 
711  /*
712  * handle distincts by inserting each operand into a list file,
713  * which will be distinct-ified and counted/summed/averaged
714  * in qdata_finalize_aggregate_list ()
715  */
716  if (agg_p->option == Q_DISTINCT || agg_p->sort_list != NULL)
717  {
718  /* convert domain to the median domains (number, date/time) to make 1,2,11 '1','2','11' result the same */
719  if (QPROC_IS_INTERPOLATION_FUNC (agg_p))
720  {
721  /* never be null type */
722  assert (!DB_IS_NULL (db_value_p));
723 
724  error = qdata_update_agg_interpolation_func_value_and_domain (agg_p, db_value_p);
725  if (error != NO_ERROR)
726  {
727  pr_clear_value_vector (db_values);
728  return ER_FAILED;
729  }
730  }
731 
732  dbval_type = DB_VALUE_DOMAIN_TYPE (db_value_p);
733  pr_type_p = pr_type_from_id (dbval_type);
734 
735  if (pr_type_p == NULL)
736  {
737  pr_clear_value_vector (db_values);
738  return ER_FAILED;
739  }
740 
741  dbval_size = pr_data_writeval_disk_size (db_value_p);
742  if (dbval_size > 0 && (disk_repr_p = (char *) db_private_alloc (thread_p, dbval_size)) != NULL)
743  {
744  OR_BUF_INIT (buf, disk_repr_p, dbval_size);
745  error = pr_type_p->data_writeval (&buf, db_value_p);
746  if (error != NO_ERROR)
747  {
748  /* ER_TF_BUFFER_OVERFLOW means that val_size or packing is bad. */
749  assert (error != ER_TF_BUFFER_OVERFLOW);
750 
751  db_private_free_and_init (thread_p, disk_repr_p);
752  pr_clear_value_vector (db_values);
753  return ER_FAILED;
754  }
755  }
756  else
757  {
758  pr_clear_value_vector (db_values);
759  return ER_FAILED;
760  }
761 
762  if (qfile_add_item_to_list (thread_p, disk_repr_p, dbval_size, agg_p->list_id) != NO_ERROR)
763  {
764  db_private_free_and_init (thread_p, disk_repr_p);
765  pr_clear_value_vector (db_values);
766  return ER_FAILED;
767  }
768 
769  db_private_free_and_init (thread_p, disk_repr_p);
770  pr_clear_value_vector (db_values);
771 
772  /* for PERCENTILE funcs, we have to check percentile value */
773  if (agg_p->function != PT_PERCENTILE_CONT && agg_p->function != PT_PERCENTILE_DISC)
774  {
775  continue;
776  }
777  }
778 
779  if (QPROC_IS_INTERPOLATION_FUNC (agg_p))
780  {
781  percentile = &agg_p->info.percentile;
782  /* when build value */
783  if (agg_p->function == PT_PERCENTILE_CONT || agg_p->function == PT_PERCENTILE_DISC)
784  {
785  assert (percentile->percentile_reguvar != NULL);
786 
787  error = fetch_peek_dbval (thread_p, percentile->percentile_reguvar, val_desc_p, NULL, NULL, NULL,
788  &percentile_val);
789  if (error != NO_ERROR)
790  {
791  assert (er_errid () != NO_ERROR);
792 
793  return ER_FAILED;
794  }
795  }
796 
797  if (agg_p->accumulator.curr_cnt < 1)
798  {
799  if (agg_p->function == PT_PERCENTILE_CONT || agg_p->function == PT_PERCENTILE_DISC)
800  {
801  if (DB_VALUE_TYPE (percentile_val) != DB_TYPE_DOUBLE)
802  {
804  return ER_FAILED;
805  }
806 
807  percentile->cur_group_percentile = db_get_double (percentile_val);
808  if (percentile->cur_group_percentile < 0 || percentile->cur_group_percentile > 1)
809  {
811  percentile->cur_group_percentile);
812  return ER_FAILED;
813  }
814  }
815 
816  if (agg_p->sort_list == NULL)
817  {
818  TP_DOMAIN *tmp_domain_p = NULL;
819  TP_DOMAIN_STATUS status;
820 
821  /* host var or constant */
822  switch (agg_p->opr_dbtype)
823  {
824  case DB_TYPE_SHORT:
825  case DB_TYPE_INTEGER:
826  case DB_TYPE_BIGINT:
827  case DB_TYPE_FLOAT:
828  case DB_TYPE_DOUBLE:
829  case DB_TYPE_MONETARY:
830  case DB_TYPE_NUMERIC:
831  case DB_TYPE_DATE:
832  case DB_TYPE_DATETIME:
833  case DB_TYPE_DATETIMELTZ:
834  case DB_TYPE_DATETIMETZ:
835  case DB_TYPE_TIMESTAMP:
837  case DB_TYPE_TIMESTAMPTZ:
838  case DB_TYPE_TIME:
839  break;
840  default:
841  assert (agg_p->operands->value.type == TYPE_CONSTANT ||
842  agg_p->operands->value.type == TYPE_DBVAL);
843 
844  /* try to cast dbval to double, datetime then time */
845  tmp_domain_p = tp_domain_resolve_default (DB_TYPE_DOUBLE);
846 
847  status = tp_value_cast (db_value_p, db_value_p, tmp_domain_p, false);
848  if (status != DOMAIN_COMPATIBLE)
849  {
850  /* try datetime */
852 
853  status = tp_value_cast (db_value_p, db_value_p, tmp_domain_p, false);
854  }
855 
856  /* try time */
857  if (status != DOMAIN_COMPATIBLE)
858  {
859  tmp_domain_p = tp_domain_resolve_default (DB_TYPE_TIME);
860 
861  status = tp_value_cast (db_value_p, db_value_p, tmp_domain_p, false);
862  }
863 
864  if (status != DOMAIN_COMPATIBLE)
865  {
868  fcode_get_uppercase_name (agg_p->function), "DOUBLE, DATETIME, TIME");
869 
870  pr_clear_value_vector (db_values);
871  return error;
872  }
873 
874  /* update domain */
875  agg_p->domain = tmp_domain_p;
876  }
877 
879  error = pr_clone_value (db_value_p, agg_p->accumulator.value);
880  if (error != NO_ERROR)
881  {
882  pr_clear_value_vector (db_values);
883  return error;
884  }
885  }
886  }
887 
888  /* clear value */
889  pr_clear_value_vector (db_values);
890 
891  /* percentile value check */
892  if (agg_p->function == PT_PERCENTILE_CONT || agg_p->function == PT_PERCENTILE_DISC)
893  {
894  if (DB_VALUE_TYPE (percentile_val) != DB_TYPE_DOUBLE
895  || db_get_double (percentile_val) != percentile->cur_group_percentile)
896  {
898  return ER_FAILED;
899  }
900  }
901  }
902  else if (agg_p->function == PT_GROUP_CONCAT)
903  {
904  assert (alt_acc_list == NULL);
905 
906  /* group concat function requires special care */
907  if (agg_p->accumulator.curr_cnt < 1)
908  {
909  error = qdata_group_concat_first_value (thread_p, agg_p, db_value_p);
910  }
911  else
912  {
913  error = qdata_group_concat_value (thread_p, agg_p, db_value_p);
914  }
915 
916  /* increment tuple count */
917  agg_p->accumulator.curr_cnt++;
918 
919  /* clear value */
920  pr_clear_value_vector (db_values);
921 
922  /* check error */
923  if (error != NO_ERROR)
924  {
925  return error;
926  }
927  }
928  else
929  {
930  /* aggregate value */
931  error = qdata_aggregate_multiple_values_to_accumulator (thread_p, accumulator, &agg_p->accumulator_domain,
932  agg_p->function, agg_p->domain, db_values);
933 
934  /* increment tuple count */
935  accumulator->curr_cnt++;
936 
937  /* clear values */
938  pr_clear_value_vector (db_values);
939 
940  /* handle error */
941  if (error != NO_ERROR)
942  {
943  return error;
944  }
945  }
946  }
947 
948  return NO_ERROR;
949 }
950 
951 /*
952  * qdata_evaluate_aggregate_optimize () -
953  * return:
954  * agg_ptr(in) :
955  * hfid(in) :
956  * super_oid(in): The super oid of a class. This should be used when dealing
957  * with a partition class. It the index is a global index,
958  * the min/max value from the partition in this case
959  * will be retrieved from the heap.
960  */
961 int
963  OID *super_oid)
964 {
965  int oid_count = 0, null_count = 0, key_count = 0;
966  int flag_btree_stat_needed = true;
967 
968  if (!agg_p->flag_agg_optimize)
969  {
970  return ER_FAILED;
971  }
972 
973  if (hfid_p->vfid.fileid < 0)
974  {
975  return ER_FAILED;
976  }
977 
978  if ((agg_p->function == PT_MIN) || (agg_p->function == PT_MAX))
979  {
980  flag_btree_stat_needed = false;
981  }
982 
983  if (flag_btree_stat_needed)
984  {
985  if (BTID_IS_NULL (&agg_p->btid))
986  {
987  return ER_FAILED;
988  }
989 
990  if (btree_get_unique_statistics_for_count (thread_p, &agg_p->btid, &oid_count, &null_count, &key_count) !=
991  NO_ERROR)
992  {
993  return ER_FAILED;
994  }
995  }
996 
997  switch (agg_p->function)
998  {
999  case PT_COUNT:
1000  if (agg_p->option == Q_ALL)
1001  {
1002  db_make_int (agg_p->accumulator.value, oid_count - null_count);
1003  }
1004  else
1005  {
1006  db_make_int (agg_p->accumulator.value, key_count);
1007  }
1008  break;
1009 
1010  case PT_COUNT_STAR:
1011  agg_p->accumulator.curr_cnt = oid_count;
1012  break;
1013 
1014  case PT_MIN:
1015  if (btree_find_min_or_max_key (thread_p, &agg_p->btid, agg_p->accumulator.value, true) != NO_ERROR)
1016  {
1017  return ER_FAILED;
1018  }
1019  break;
1020 
1021  case PT_MAX:
1022  if (btree_find_min_or_max_key (thread_p, &agg_p->btid, agg_p->accumulator.value, false) != NO_ERROR)
1023  {
1024  return ER_FAILED;
1025  }
1026  break;
1027 
1028  default:
1029  break;
1030  }
1031 
1032  return NO_ERROR;
1033 }
1034 
1035 /*
1036  * qdata_evaluate_aggregate_hierarchy () - aggregate evaluation optimization
1037  * across a class hierarchy
1038  * return : error code or NO_ERROR
1039  * thread_p (in) : thread entry
1040  * agg_p (in) : aggregate to be evaluated
1041  * root_hfid (in) : HFID of the root class in the hierarchy
1042  * root_btid (in) : BTID of the root class in the hierarchy
1043  * helper (in) : hierarchy helper
1044  */
1045 int
1047  BTID *root_btid, hierarchy_aggregate_helper *helper)
1048 {
1049  int error = NO_ERROR, i, cmp = DB_EQ, cur_cnt = 0;
1050  DB_VALUE result;
1051  if (!agg_p->flag_agg_optimize)
1052  {
1053  return ER_FAILED;
1054  }
1055 
1056  /* evaluate aggregate on the root class */
1057  error = qdata_evaluate_aggregate_optimize (thread_p, agg_p, root_hfid, NULL);
1058  if (error != NO_ERROR)
1059  {
1060  return error;
1061  }
1062 
1063  db_make_null (&result);
1064  error = pr_clone_value (agg_p->accumulator.value, &result);
1065  if (error != NO_ERROR)
1066  {
1067  return error;
1068  }
1069 
1070  pr_clear_value (agg_p->accumulator.value);
1071  /* iterate through classes in the hierarchy and merge aggregate values */
1072  for (i = 0; i < helper->count && error == NO_ERROR; i++)
1073  {
1074  if (!BTID_IS_NULL (&agg_p->btid))
1075  {
1076  assert (helper->btids != NULL);
1077  BTID_COPY (&agg_p->btid, &helper->btids[i]);
1078  }
1079  error = qdata_evaluate_aggregate_optimize (thread_p, agg_p, &helper->hfids[i], NULL);
1080  if (error != NO_ERROR)
1081  {
1082  goto cleanup;
1083  }
1084  switch (agg_p->function)
1085  {
1086  case PT_COUNT:
1087  /* add current value to result */
1088  error = qdata_add_dbval (agg_p->accumulator.value, &result, &result, agg_p->domain);
1089  pr_clear_value (agg_p->accumulator.value);
1090  break;
1091  case PT_COUNT_STAR:
1092  cur_cnt += agg_p->accumulator.curr_cnt;
1093  break;
1094  case PT_MIN:
1095  if (DB_IS_NULL (&result))
1096  {
1097  error = pr_clone_value (agg_p->accumulator.value, &result);
1098  if (error != NO_ERROR)
1099  {
1100  goto cleanup;
1101  }
1102  }
1103  else
1104  {
1105 
1106  cmp = tp_value_compare (agg_p->accumulator.value, &result, true, true);
1107  if (cmp == DB_LT)
1108  {
1109  /* agg_p->value is lower than result so make it the new minimum */
1110  pr_clear_value (&result);
1111  error = pr_clone_value (agg_p->accumulator.value, &result);
1112  if (error != NO_ERROR)
1113  {
1114  goto cleanup;
1115  }
1116  }
1117  }
1118  break;
1119 
1120  case PT_MAX:
1121  if (DB_IS_NULL (&result))
1122  {
1123  error = pr_clone_value (agg_p->accumulator.value, &result);
1124  if (error != NO_ERROR)
1125  {
1126  goto cleanup;
1127  }
1128  }
1129  else
1130  {
1131  cmp = tp_value_compare (agg_p->accumulator.value, &result, true, true);
1132  if (cmp == DB_GT)
1133  {
1134  /* agg_p->value is greater than result so make it the new maximum */
1135  pr_clear_value (&result);
1136  error = pr_clone_value (agg_p->accumulator.value, &result);
1137  if (error != NO_ERROR)
1138  {
1139  goto cleanup;
1140  }
1141  }
1142  }
1143  break;
1144 
1145  default:
1146  break;
1147  }
1148  pr_clear_value (agg_p->accumulator.value);
1149  }
1150 
1151  if (agg_p->function == PT_COUNT_STAR)
1152  {
1153  agg_p->accumulator.curr_cnt = cur_cnt;
1154  }
1155  else
1156  {
1157  pr_clone_value (&result, agg_p->accumulator.value);
1158  }
1159 
1160 cleanup:
1161  pr_clear_value (&result);
1162 
1163  if (!BTID_IS_NULL (&agg_p->btid))
1164  {
1165  /* restore btid of agg_p */
1166  BTID_COPY (&agg_p->btid, root_btid);
1167  }
1168  return error;
1169 }
1170 
1171 /*
1172  * qdata_finalize_aggregate_list () -
1173  * return: NO_ERROR, or ER_code
1174  * agg_list(in) : Aggregate expression node list
1175  * keep_list_file(in) : whether keep the list file for reuse
1176  *
1177  * Note: Make the final evaluation on the aggregate expression list.
1178  */
1179 int
1181  bool keep_list_file)
1182 {
1183  int error = NO_ERROR;
1184  AGGREGATE_TYPE *agg_p;
1185  DB_VALUE sqr_val;
1186  DB_VALUE dbval;
1187  DB_VALUE xavgval, xavg_1val, x2avgval;
1188  DB_VALUE xavg2val, varval;
1189  DB_VALUE dval;
1190  double dtmp;
1191  QFILE_LIST_ID *list_id_p;
1192  QFILE_LIST_SCAN_ID scan_id;
1193  SCAN_CODE scan_code;
1194  QFILE_TUPLE_RECORD tuple_record = { NULL, 0 };
1195  char *tuple_p;
1196  PR_TYPE *pr_type_p;
1197  OR_BUF buf;
1198  double dbl;
1199 
1200  db_make_null (&sqr_val);
1201  db_make_null (&dbval);
1202  db_make_null (&xavgval);
1203  db_make_null (&xavg_1val);
1204  db_make_null (&x2avgval);
1205  db_make_null (&xavg2val);
1206  db_make_null (&varval);
1207  db_make_null (&dval);
1208 
1209  for (agg_p = agg_list_p; agg_p != NULL; agg_p = agg_p->next)
1210  {
1211  TP_DOMAIN *tmp_domain_ptr = NULL;
1212 
1213  if (agg_p->function == PT_VARIANCE || agg_p->function == PT_STDDEV || agg_p->function == PT_VAR_POP
1214  || agg_p->function == PT_STDDEV_POP || agg_p->function == PT_VAR_SAMP || agg_p->function == PT_STDDEV_SAMP)
1215  {
1216  tmp_domain_ptr = tp_domain_resolve_default (DB_TYPE_DOUBLE);
1217  }
1218 
1219  /* set count-star aggregate values */
1220  if (agg_p->function == PT_COUNT_STAR)
1221  {
1223  }
1224 
1225  /* the value of groupby_num() remains unchanged; it will be changed while evaluating groupby_num predicates
1226  * against each group at 'xs_eval_grbynum_pred()' */
1227  if (agg_p->function == PT_GROUPBY_NUM)
1228  {
1229  /* nothing to do with groupby_num() */
1230  continue;
1231  }
1232 
1233  if (agg_p->function == PT_CUME_DIST)
1234  {
1235  /* calculate the result for CUME_DIST */
1236  dbl = (double) (agg_p->info.dist_percent.nlargers + 1) / (agg_p->accumulator.curr_cnt + 1);
1237  assert (dbl <= 1.0 && dbl > 0.0);
1238  db_make_double (agg_p->accumulator.value, dbl);
1239 
1240  /* free const_array */
1241  if (agg_p->info.dist_percent.const_array != NULL)
1242  {
1243  db_private_free_and_init (thread_p, agg_p->info.dist_percent.const_array);
1244  agg_p->info.dist_percent.list_len = 0;
1245  }
1246  continue;
1247  }
1248  else if (agg_p->function == PT_PERCENT_RANK)
1249  {
1250  /* calculate the result for PERCENT_RANK */
1251  if (agg_p->accumulator.curr_cnt == 0)
1252  {
1253  dbl = 0.0;
1254  }
1255  else
1256  {
1257  dbl = (double) (agg_p->info.dist_percent.nlargers) / agg_p->accumulator.curr_cnt;
1258  }
1259  assert (dbl <= 1.0 && dbl >= 0.0);
1260  db_make_double (agg_p->accumulator.value, dbl);
1261 
1262  /* free const_array */
1263  if (agg_p->info.dist_percent.const_array != NULL)
1264  {
1265  db_private_free_and_init (thread_p, agg_p->info.dist_percent.const_array);
1266  agg_p->info.dist_percent.list_len = 0;
1267  }
1268  continue;
1269  }
1270 
1271  /* process list file for sum/avg/count distinct */
1272  if ((agg_p->option == Q_DISTINCT || agg_p->sort_list != NULL) && agg_p->function != PT_MAX
1273  && agg_p->function != PT_MIN)
1274  {
1275  if (agg_p->sort_list != NULL
1278  {
1279  /* set domain of SORT LIST same as the domain from agg list */
1281  agg_p->sort_list->pos_descr.dom = agg_p->list_id->type_list.domp[agg_p->sort_list->pos_descr.pos_no];
1282  }
1283 
1284  if (agg_p->flag_agg_optimize == false)
1285  {
1286  list_id_p = qfile_sort_list (thread_p, agg_p->list_id, agg_p->sort_list, agg_p->option, false);
1287 
1288  if (list_id_p != NULL && er_has_error ())
1289  {
1290  /* Some unexpected errors (like ER_INTERRUPTED due to timeout) should be handled. */
1291  qfile_close_list (thread_p, list_id_p);
1292  qfile_destroy_list (thread_p, list_id_p);
1293  list_id_p = NULL;
1294  ASSERT_ERROR_AND_SET (error);
1295  goto exit;
1296  }
1297 
1298  if (list_id_p == NULL)
1299  {
1300  if (!er_has_error ())
1301  {
1303  }
1304 
1305  ASSERT_ERROR_AND_SET (error);
1306  goto exit;
1307  }
1308 
1309  agg_p->list_id = list_id_p;
1310 
1311  if (agg_p->function == PT_COUNT)
1312  {
1313  db_make_int (agg_p->accumulator.value, list_id_p->tuple_cnt);
1314  }
1315  else
1316  {
1317  pr_type_p = list_id_p->type_list.domp[0]->type;
1318 
1319  /* scan list file, accumulating total for sum/avg */
1320  error = qfile_open_list_scan (list_id_p, &scan_id);
1321  if (error != NO_ERROR)
1322  {
1323  ASSERT_ERROR ();
1324  qfile_close_list (thread_p, list_id_p);
1325  qfile_destroy_list (thread_p, list_id_p);
1326  goto exit;
1327  }
1328 
1329  /* median and percentile funcs don't need to read all rows */
1330  if (list_id_p->tuple_cnt > 0 && QPROC_IS_INTERPOLATION_FUNC (agg_p))
1331  {
1332  error = qdata_aggregate_interpolation (thread_p, agg_p, &scan_id);
1333  if (error != NO_ERROR)
1334  {
1335  ASSERT_ERROR ();
1336  qfile_close_scan (thread_p, &scan_id);
1337  qfile_close_list (thread_p, list_id_p);
1338  qfile_destroy_list (thread_p, list_id_p);
1339  goto exit;
1340  }
1341  }
1342  else
1343  {
1344  while (true)
1345  {
1346  scan_code = qfile_scan_list_next (thread_p, &scan_id, &tuple_record, PEEK);
1347 
1348  if (scan_code == S_ERROR && er_has_error ())
1349  {
1350  /* Some unexpected errors (like ER_INTERRUPTED due to timeout) should be handled. */
1351  ASSERT_ERROR_AND_SET (error);
1352  qfile_close_scan (thread_p, &scan_id);
1353  qfile_close_list (thread_p, list_id_p);
1354  qfile_destroy_list (thread_p, list_id_p);
1355  goto exit;
1356  }
1357 
1358  if (scan_code != S_SUCCESS)
1359  {
1360  break;
1361  }
1362 
1363  tuple_p = ((char *) tuple_record.tpl + QFILE_TUPLE_LENGTH_SIZE);
1364  if (QFILE_GET_TUPLE_VALUE_FLAG (tuple_p) == V_UNBOUND)
1365  {
1366  continue;
1367  }
1368 
1369  or_init (&buf, (char *) tuple_p + QFILE_TUPLE_VALUE_HEADER_SIZE,
1370  QFILE_GET_TUPLE_VALUE_LENGTH (tuple_p));
1371 
1372  (void) pr_clear_value (&dbval);
1373  error = pr_type_p->data_readval (&buf, &dbval, list_id_p->type_list.domp[0], -1, true, NULL,
1374  0);
1375  if (error != NO_ERROR)
1376  {
1377  ASSERT_ERROR ();
1378  qfile_close_scan (thread_p, &scan_id);
1379  qfile_close_list (thread_p, list_id_p);
1380  qfile_destroy_list (thread_p, list_id_p);
1381  goto exit;
1382  }
1383 
1384  if (agg_p->function == PT_VARIANCE || agg_p->function == PT_STDDEV
1385  || agg_p->function == PT_VAR_POP || agg_p->function == PT_STDDEV_POP
1386  || agg_p->function == PT_VAR_SAMP || agg_p->function == PT_STDDEV_SAMP)
1387  {
1388  if (tp_value_coerce (&dbval, &dbval, tmp_domain_ptr) != DOMAIN_COMPATIBLE)
1389  {
1390  ASSERT_ERROR_AND_SET (error);
1391  (void) pr_clear_value (&dbval);
1392  qfile_close_scan (thread_p, &scan_id);
1393  qfile_close_list (thread_p, list_id_p);
1394  qfile_destroy_list (thread_p, list_id_p);
1395  goto exit;
1396  }
1397  }
1398 
1399  if (DB_IS_NULL (agg_p->accumulator.value))
1400  {
1401  /* first iteration: can't add to a null agg_ptr->value */
1402  PR_TYPE *tmp_pr_type;
1403  DB_TYPE dbval_type = DB_VALUE_DOMAIN_TYPE (&dbval);
1404 
1405  tmp_pr_type = pr_type_from_id (dbval_type);
1406  if (tmp_pr_type == NULL)
1407  {
1408  ASSERT_ERROR_AND_SET (error);
1409  (void) pr_clear_value (&dbval);
1410  qfile_close_scan (thread_p, &scan_id);
1411  qfile_close_list (thread_p, list_id_p);
1412  qfile_destroy_list (thread_p, list_id_p);
1413  goto exit;
1414  }
1415 
1416  if (agg_p->function == PT_STDDEV || agg_p->function == PT_VARIANCE
1417  || agg_p->function == PT_STDDEV_POP || agg_p->function == PT_VAR_POP
1418  || agg_p->function == PT_STDDEV_SAMP || agg_p->function == PT_VAR_SAMP)
1419  {
1420  error = qdata_multiply_dbval (&dbval, &dbval, &sqr_val, tmp_domain_ptr);
1421  if (error != NO_ERROR)
1422  {
1423  ASSERT_ERROR ();
1424  (void) pr_clear_value (&dbval);
1425  qfile_close_scan (thread_p, &scan_id);
1426  qfile_close_list (thread_p, list_id_p);
1427  qfile_destroy_list (thread_p, list_id_p);
1428  goto exit;
1429  }
1430 
1431  if (tmp_pr_type->setval (agg_p->accumulator.value2, &sqr_val, true) != NO_ERROR)
1432  {
1433  assert (false);
1434  error = ER_FAILED;
1435  goto exit;
1436  }
1437  }
1438  if (agg_p->function == PT_GROUP_CONCAT)
1439  {
1440  error = qdata_group_concat_first_value (thread_p, agg_p, &dbval);
1441  if (error != NO_ERROR)
1442  {
1443  ASSERT_ERROR ();
1444  (void) pr_clear_value (&dbval);
1445  qfile_close_scan (thread_p, &scan_id);
1446  qfile_close_list (thread_p, list_id_p);
1447  qfile_destroy_list (thread_p, list_id_p);
1448  goto exit;
1449  }
1450  }
1451  else
1452  {
1453  if (tmp_pr_type->setval (agg_p->accumulator.value, &dbval, true) != NO_ERROR)
1454  {
1455  assert (false);
1456  error = ER_FAILED;
1457  goto exit;
1458  }
1459  }
1460  }
1461  else
1462  {
1463  if (agg_p->function == PT_STDDEV || agg_p->function == PT_VARIANCE
1464  || agg_p->function == PT_STDDEV_POP || agg_p->function == PT_VAR_POP
1465  || agg_p->function == PT_STDDEV_SAMP || agg_p->function == PT_VAR_SAMP)
1466  {
1467  error = qdata_multiply_dbval (&dbval, &dbval, &sqr_val, tmp_domain_ptr);
1468  if (error != NO_ERROR)
1469  {
1470  ASSERT_ERROR ();
1471  (void) pr_clear_value (&dbval);
1472  qfile_close_scan (thread_p, &scan_id);
1473  qfile_close_list (thread_p, list_id_p);
1474  qfile_destroy_list (thread_p, list_id_p);
1475  goto exit;
1476  }
1477 
1478  error = qdata_add_dbval (agg_p->accumulator.value2, &sqr_val,
1479  agg_p->accumulator.value2, tmp_domain_ptr);
1480  if (error != NO_ERROR)
1481  {
1482  ASSERT_ERROR ();
1483  (void) pr_clear_value (&dbval);
1484  (void) pr_clear_value (&sqr_val);
1485  qfile_close_scan (thread_p, &scan_id);
1486  qfile_close_list (thread_p, list_id_p);
1487  qfile_destroy_list (thread_p, list_id_p);
1488  goto exit;
1489  }
1490  }
1491 
1492  if (agg_p->function == PT_GROUP_CONCAT)
1493  {
1494  error = qdata_group_concat_value (thread_p, agg_p, &dbval);
1495  if (error != NO_ERROR)
1496  {
1497  ASSERT_ERROR ();
1498  (void) pr_clear_value (&dbval);
1499  qfile_close_scan (thread_p, &scan_id);
1500  qfile_close_list (thread_p, list_id_p);
1501  qfile_destroy_list (thread_p, list_id_p);
1502  goto exit;
1503  }
1504  }
1505  else
1506  {
1507 
1508  TP_DOMAIN *domain_ptr =
1509  tmp_domain_ptr != NULL ? tmp_domain_ptr : agg_p->accumulator_domain.value_dom;
1510  /* accumulator domain should be used instead of agg_p->domain for SUM/AVG evaluation
1511  * at the end cast the result to agg_p->domain */
1512  if ((agg_p->function == PT_AVG)
1513  && (dbval.domain.general_info.type == DB_TYPE_NUMERIC))
1514  {
1515  domain_ptr = NULL;
1516  }
1517 
1518  error = qdata_add_dbval (agg_p->accumulator.value, &dbval,
1519  agg_p->accumulator.value, domain_ptr);
1520  if (error != NO_ERROR)
1521  {
1522  ASSERT_ERROR ();
1523  (void) pr_clear_value (&dbval);
1524  qfile_close_scan (thread_p, &scan_id);
1525  qfile_close_list (thread_p, list_id_p);
1526  qfile_destroy_list (thread_p, list_id_p);
1527  goto exit;
1528  }
1529  }
1530  }
1531  } /* while (true) */
1532  }
1533 
1534  qfile_close_scan (thread_p, &scan_id);
1535  agg_p->accumulator.curr_cnt = list_id_p->tuple_cnt;
1536  }
1537  }
1538 
1539  /* close and destroy temporary list files */
1540  if (!keep_list_file)
1541  {
1542  qfile_close_list (thread_p, agg_p->list_id);
1543  qfile_destroy_list (thread_p, agg_p->list_id);
1544  }
1545  }
1546 
1547  if (agg_p->function == PT_GROUP_CONCAT && !DB_IS_NULL (agg_p->accumulator.value))
1548  {
1550  }
1551  /* compute averages */
1552  if (agg_p->accumulator.curr_cnt > 0
1553  && (agg_p->function == PT_AVG || agg_p->function == PT_STDDEV || agg_p->function == PT_VARIANCE
1554  || agg_p->function == PT_STDDEV_POP || agg_p->function == PT_VAR_POP || agg_p->function == PT_STDDEV_SAMP
1555  || agg_p->function == PT_VAR_SAMP))
1556  {
1557  TP_DOMAIN *double_domain_ptr = tp_domain_resolve_default (DB_TYPE_DOUBLE);
1558 
1559  /* compute AVG(X) = SUM(X)/COUNT(X) */
1560  db_make_double (&dbval, agg_p->accumulator.curr_cnt);
1561  error = qdata_divide_dbval (agg_p->accumulator.value, &dbval, &xavgval, double_domain_ptr);
1562  if (error != NO_ERROR)
1563  {
1564  ASSERT_ERROR ();
1565  goto exit;
1566  }
1567 
1568  if (agg_p->function == PT_AVG)
1569  {
1570  if (tp_value_coerce (&xavgval, agg_p->accumulator.value, double_domain_ptr) != DOMAIN_COMPATIBLE)
1571  {
1572  ASSERT_ERROR_AND_SET (error);
1573  goto exit;
1574  }
1575 
1576  continue;
1577  }
1578 
1579  if (agg_p->function == PT_STDDEV_SAMP || agg_p->function == PT_VAR_SAMP)
1580  {
1581  /* compute SUM(X^2) / (n-1) */
1582  if (agg_p->accumulator.curr_cnt > 1)
1583  {
1584  db_make_double (&dbval, agg_p->accumulator.curr_cnt - 1);
1585  }
1586  else
1587  {
1588  /* when not enough samples, return NULL */
1589  db_make_null (agg_p->accumulator.value);
1590  continue;
1591  }
1592  }
1593  else
1594  {
1595  assert (agg_p->function == PT_STDDEV || agg_p->function == PT_STDDEV_POP || agg_p->function == PT_VARIANCE
1596  || agg_p->function == PT_VAR_POP);
1597  /* compute SUM(X^2) / n */
1598  db_make_double (&dbval, agg_p->accumulator.curr_cnt);
1599  }
1600 
1601  error = qdata_divide_dbval (agg_p->accumulator.value2, &dbval, &x2avgval, double_domain_ptr);
1602  if (error != NO_ERROR)
1603  {
1604  ASSERT_ERROR ();
1605  goto exit;
1606  }
1607 
1608  /* compute {SUM(X) / (n)} OR {SUM(X) / (n-1)} for xxx_SAMP agg */
1609  error = qdata_divide_dbval (agg_p->accumulator.value, &dbval, &xavg_1val, double_domain_ptr);
1610  if (error != NO_ERROR)
1611  {
1612  ASSERT_ERROR ();
1613  goto exit;
1614  }
1615 
1616  /* compute AVG(X) * {SUM(X) / (n)} , AVG(X) * {SUM(X) / (n-1)} for xxx_SAMP agg */
1617  error = qdata_multiply_dbval (&xavgval, &xavg_1val, &xavg2val, double_domain_ptr);
1618  if (error != NO_ERROR)
1619  {
1620  ASSERT_ERROR ();
1621  goto exit;
1622  }
1623 
1624  /* compute VAR(X) = SUM(X^2)/(n) - AVG(X) * {SUM(X) / (n)} OR VAR(X) = SUM(X^2)/(n-1) - AVG(X) * {SUM(X) /
1625  * (n-1)} for xxx_SAMP aggregates */
1626  error = qdata_subtract_dbval (&x2avgval, &xavg2val, &varval, double_domain_ptr);
1627  if (error != NO_ERROR)
1628  {
1629  ASSERT_ERROR ();
1630  goto exit;
1631  }
1632 
1633  if (agg_p->function == PT_VARIANCE || agg_p->function == PT_STDDEV || agg_p->function == PT_VAR_POP
1634  || agg_p->function == PT_STDDEV_POP || agg_p->function == PT_VAR_SAMP
1635  || agg_p->function == PT_STDDEV_SAMP)
1636  {
1637  pr_clone_value (&varval, agg_p->accumulator.value);
1638  }
1639 
1640  if (agg_p->function == PT_STDDEV || agg_p->function == PT_STDDEV_POP || agg_p->function == PT_STDDEV_SAMP)
1641  {
1642  TP_DOMAIN *tmp_domain_ptr;
1643 
1645  /* Construct TP_DOMAIN whose type is DB_TYPE_DOUBLE */
1646  tmp_domain_ptr = tp_domain_resolve_default (DB_TYPE_DOUBLE);
1647  if (tp_value_coerce (&varval, &dval, tmp_domain_ptr) != DOMAIN_COMPATIBLE)
1648  {
1649  ASSERT_ERROR_AND_SET (error);
1650  goto exit;
1651  }
1652 
1653  dtmp = db_get_double (&dval);
1654 
1655  /* mathematically, dtmp should be zero or positive; however, due to some precision errors, in some cases
1656  * it can be a very small negative number of which we cannot extract the square root */
1657  dtmp = (dtmp < 0.0f ? 0.0f : dtmp);
1658 
1659  dtmp = sqrt (dtmp);
1660  db_make_double (&dval, dtmp);
1661 
1662  pr_clone_value (&dval, agg_p->accumulator.value);
1663  }
1664  }
1665 
1666  /* Resolve the final result of aggregate function. Since the evaluation value might be changed to keep the
1667  * precision during the aggregate function evaluation, for example, use DOUBLE instead FLOAT, we need to cast the
1668  * result to the original domain. */
1669  if (agg_p->function == PT_SUM && agg_p->domain != agg_p->accumulator_domain.value_dom)
1670  {
1671  /* cast value */
1672  error = db_value_coerce (agg_p->accumulator.value, agg_p->accumulator.value, agg_p->domain);
1673  if (error != NO_ERROR)
1674  {
1675  ASSERT_ERROR ();
1676  return ER_FAILED;
1677  }
1678  }
1679  }
1680 
1681 exit:
1682  if (error != NO_ERROR)
1683  {
1684  // make sure all list ids are cleared
1685  for (agg_p = agg_list_p; agg_p != NULL; agg_p = agg_p->next)
1686  {
1687  qfile_close_list (thread_p, agg_p->list_id);
1688  qfile_destroy_list (thread_p, agg_p->list_id);
1689  }
1690  }
1691 
1692  (void) pr_clear_value (&dbval);
1693 
1694  return error;
1695 }
1696 
1697 /*
1698  * qdata_calculate_aggregate_cume_dist_percent_rank () -
1699  * return: NO_ERROR, or ER_code
1700  * agg_p(in): aggregate type
1701  * val_desc_p(in):
1702  *
1703  */
1704 static int
1706  VAL_DESCR *val_desc_p)
1707 {
1708  DB_VALUE *val_node, **val_node_p;
1709  int *len;
1710  int i, nloops, cmp;
1711  REGU_VARIABLE_LIST regu_var_list, regu_var_node, regu_tmp_node;
1712  AGGREGATE_DIST_PERCENT_INFO *info_p;
1713  PR_TYPE *pr_type_p;
1714  SORT_LIST *sort_p;
1715  SORT_ORDER s_order;
1716  SORT_NULLS s_nulls;
1717  DB_DOMAIN *dom;
1718  HL_HEAPID save_heapid = 0;
1719 
1720  assert (agg_p != NULL && agg_p->sort_list != NULL && agg_p->operands->value.type == TYPE_REGU_VAR_LIST);
1721 
1722  regu_var_list = agg_p->operands->value.value.regu_var_list;
1723  info_p = &agg_p->info.dist_percent;
1724  assert (regu_var_list != NULL && info_p != NULL);
1725 
1726  sort_p = agg_p->sort_list;
1727  assert (sort_p != NULL);
1728 
1729  /* for the first time, init */
1730  if (agg_p->accumulator.curr_cnt == 0)
1731  {
1732  /* first split the const list and type list: CUME_DIST and PERCENT_RANK is defined as: CUME_DIST( const_list)
1733  * WITHIN GROUP (ORDER BY type_list) ... const list: the hypothetical values for calculation type list: field
1734  * name given in the ORDER BY clause; All these information is store in the agg_p->operand.value.regu_var_list;
1735  * First N values are type_list, and the last N values are const_list. */
1736  assert (info_p->list_len == 0 && info_p->const_array == NULL);
1737 
1738  regu_var_node = regu_tmp_node = regu_var_list;
1739  len = &info_p->list_len;
1740  info_p->nlargers = 0;
1741  nloops = 0;
1742 
1743  /* find the length of the type list and const list */
1744  while (regu_tmp_node)
1745  {
1746  ++nloops;
1747  regu_var_node = regu_var_node->next;
1748  regu_tmp_node = regu_tmp_node->next->next;
1749  }
1750  *len = nloops;
1751 
1752  /* memory alloc for const array */
1753  assert (info_p->const_array == NULL);
1754  info_p->const_array = (DB_VALUE **) db_private_alloc (thread_p, nloops * sizeof (DB_VALUE *));
1755 
1756  if (info_p->const_array == NULL)
1757  {
1758  goto exit_on_error;
1759  }
1760 
1761  /* now we have found the start of the const list, fetch DB_VALUE from the list into info.dist_percent */
1762  regu_tmp_node = regu_var_list;
1763  for (i = 0; i < nloops; i++)
1764  {
1765  val_node_p = &info_p->const_array[i];
1766  if (fetch_peek_dbval (thread_p, &regu_var_node->value, val_desc_p, NULL, NULL, NULL, val_node_p) != NO_ERROR)
1767  {
1768  goto exit_on_error;
1769  }
1770 
1771  /* Note: we must cast the const value to the same domain as the compared field in the order by clause */
1772  dom = regu_tmp_node->value.domain;
1773 
1775  {
1776  save_heapid = db_change_private_heap (thread_p, 0);
1777  }
1778 
1779  if (db_value_coerce (*val_node_p, *val_node_p, dom) != NO_ERROR)
1780  {
1781  if (save_heapid != 0)
1782  {
1783  (void) db_change_private_heap (thread_p, save_heapid);
1784  save_heapid = 0;
1785  }
1786 
1787  goto exit_on_error;
1788  }
1789 
1790  if (save_heapid != 0)
1791  {
1792  (void) db_change_private_heap (thread_p, save_heapid);
1793  save_heapid = 0;
1794  }
1795 
1796  regu_var_node = regu_var_node->next;
1797  regu_tmp_node = regu_tmp_node->next;
1798  }
1799  }
1800 
1801  /* comparing the values of type list and const list */
1802  assert (info_p->list_len != 0 && info_p->const_array != NULL);
1803 
1804  regu_var_node = regu_var_list;
1805  cmp = 0;
1806  nloops = info_p->list_len;
1807 
1808  for (i = 0; i < nloops; i++)
1809  {
1810  /* Note: To handle 'nulls first/last', we need to compare NULLs values */
1811  s_order = sort_p->s_order;
1812  s_nulls = sort_p->s_nulls;
1813  sort_p = sort_p->next;
1814 
1815  if (fetch_peek_dbval (thread_p, &regu_var_node->value, val_desc_p, NULL, NULL, NULL, &val_node) != NO_ERROR)
1816  {
1817  goto exit_on_error;
1818  }
1819 
1820  /* compare the value and find the order in asc or desc */
1821  if (DB_IS_NULL (val_node) && DB_IS_NULL (info_p->const_array[i]))
1822  {
1823  /* NULL and NULL comparison */
1824  cmp = DB_EQ;
1825  }
1826  else if (!DB_IS_NULL (val_node) && DB_IS_NULL (info_p->const_array[i]))
1827  {
1828  /* non-NULL and NULL comparison */
1829  if (s_nulls == S_NULLS_LAST)
1830  {
1831  cmp = DB_LT;
1832  }
1833  else
1834  {
1835  cmp = DB_GT;
1836  }
1837  }
1838  else if (DB_IS_NULL (val_node) && !DB_IS_NULL (info_p->const_array[i]))
1839  {
1840  /* NULL and non-NULL comparison */
1841  if (s_nulls == S_NULLS_LAST)
1842  {
1843  cmp = DB_GT;
1844  }
1845  else
1846  {
1847  cmp = DB_LT;
1848  }
1849  }
1850  else
1851  {
1852  /* non-NULL values comparison */
1853  pr_type_p = pr_type_from_id (DB_VALUE_DOMAIN_TYPE (val_node));
1854  cmp = pr_type_p->cmpval (val_node, info_p->const_array[i], 1, 0, NULL,
1855  regu_var_node->value.domain->collation_id);
1856 
1857  assert (cmp != DB_UNK);
1858  }
1859 
1860  if (cmp != DB_EQ)
1861  {
1862  if (s_order == S_DESC)
1863  {
1864  /* in a descend order */
1865  cmp = -cmp;
1866  }
1867  break;
1868  }
1869  /* equal, compare next value */
1870  regu_var_node = regu_var_node->next;
1871  }
1872 
1873  switch (agg_p->function)
1874  {
1875  case PT_CUME_DIST:
1876  if (cmp <= 0)
1877  {
1878  info_p->nlargers++;
1879  }
1880  break;
1881  case PT_PERCENT_RANK:
1882  if (cmp < 0)
1883  {
1884  info_p->nlargers++;
1885  }
1886  break;
1887  default:
1888  goto exit_on_error;
1889  }
1890 
1891  agg_p->accumulator.curr_cnt++;
1892 
1893  return NO_ERROR;
1894 
1895 exit_on_error:
1896  /* error! free const_array */
1897  if (agg_p->info.dist_percent.const_array != NULL)
1898  {
1899  db_private_free_and_init (thread_p, agg_p->info.dist_percent.const_array);
1900  }
1901  return ER_FAILED;
1902 }
1903 
1904 /*
1905  * qdata_alloc_agg_hkey () - allocate new hash aggregate key
1906  * returns: pointer to new structure or NULL on error
1907  * thread_p(in): thread
1908  * val_cnt(in): size of key
1909  * alloc_vals(in): if true will allocate dbvalues
1910  */
1912 qdata_alloc_agg_hkey (cubthread::entry *thread_p, int val_cnt, bool alloc_vals)
1913 {
1914  aggregate_hash_key *key;
1915  int i;
1916 
1917  key = (aggregate_hash_key *) db_private_alloc (thread_p, sizeof (aggregate_hash_key));
1918  if (key == NULL)
1919  {
1921  return NULL;
1922  }
1923 
1924  key->values = (DB_VALUE **) db_private_alloc (thread_p, sizeof (DB_VALUE *) * val_cnt);
1925  if (key->values == NULL)
1926  {
1927  db_private_free (thread_p, key);
1929  return NULL;
1930  }
1931 
1932  if (alloc_vals)
1933  {
1934  for (i = 0; i < val_cnt; i++)
1935  {
1936  key->values[i] = pr_make_value ();
1937  }
1938  }
1939 
1940  key->val_count = val_cnt;
1941  key->free_values = alloc_vals;
1942  return key;
1943 }
1944 
1945 /*
1946  * qdata_free_agg_hkey () - free hash aggregate key
1947  * thread_p(in): thread
1948  * key(in): aggregate hash key
1949  */
1950 void
1952 {
1953  int i = 0;
1954 
1955  if (key == NULL)
1956  {
1957  return;
1958  }
1959 
1960  if (key->values != NULL)
1961  {
1962  if (key->free_values)
1963  {
1964  for (i = 0; i < key->val_count; i++)
1965  {
1966  if (key->values[i])
1967  {
1968  pr_free_value (key->values[i]);
1969  }
1970  }
1971  }
1972 
1973  /* free values array */
1974  db_private_free (thread_p, key->values);
1975  }
1976 
1977  /* free structure */
1978  db_private_free (thread_p, key);
1979 }
1980 
1981 /*
1982  * qdata_alloc_agg_hkey () - allocate new hash aggregate key
1983  * returns: pointer to new structure or NULL on error
1984  * thread_p(in): thread
1985  */
1988 {
1989  aggregate_hash_value *value;
1990  int i;
1992 
1993  /* alloc structure */
1994  value = (aggregate_hash_value *) db_private_alloc (thread_p, sizeof (aggregate_hash_value));
1995  if (value == NULL)
1996  {
1998  return NULL;
1999  }
2000 
2001  if (func_cnt > 0)
2002  {
2003  value->accumulators =
2005  sizeof (cubxasl::aggregate_accumulator) * func_cnt);
2006  if (value->accumulators == NULL)
2007  {
2008  db_private_free (thread_p, value);
2010  sizeof (cubxasl::aggregate_accumulator) * func_cnt);
2011  return NULL;
2012  }
2013  }
2014  else
2015  {
2016  value->accumulators = NULL;
2017  }
2018 
2019  value->func_count = func_cnt;
2020  /* alloc DB_VALUEs */
2021  for (i = 0; i < func_cnt; i++)
2022  {
2023  value->accumulators[i].value = pr_make_value ();
2024  value->accumulators[i].value2 = pr_make_value ();
2025  }
2026  /* initialize accumulators.value */
2027  for (i = 0, agg_p = g_agg_list; agg_p != NULL; agg_p = agg_p->next, i++)
2028  {
2029  /* CAUTION : if modify initializing ACC's value then should change qdata_initialize_aggregate_list() */
2030  if (agg_p->function == PT_GROUPBY_NUM)
2031  {
2032  /* nothing to do with groupby_num() */
2033  continue;
2034  }
2035  value->accumulators[i].curr_cnt = 0;
2036 
2037  /* This set is made, because if class is empty, aggregate results should return NULL, except count(*) and count */
2038  if (agg_p->function == PT_COUNT_STAR || agg_p->function == PT_COUNT)
2039  {
2040  db_make_int (value->accumulators[i].value, 0);
2041  }
2042  }
2043 
2044  /* initialize counter */
2045  value->tuple_count = 0;
2046 
2047  /* initialize tuple */
2048  value->first_tuple.size = 0;
2049  value->first_tuple.tpl = NULL;
2050 
2051  return value;
2052 }
2053 
2054 /*
2055  * qdata_free_agg_hkey () - free hash aggregate key
2056  * thread_p(in): thread
2057  * key(in): aggregate hash key
2058  */
2059 void
2061 {
2062  int i = 0;
2063 
2064  if (value == NULL)
2065  {
2066  return;
2067  }
2068 
2069  /* free values */
2070  if (value->accumulators != NULL)
2071  {
2072  for (i = 0; i < value->func_count; i++)
2073  {
2074  if (value->accumulators[i].value != NULL)
2075  {
2076  pr_free_value (value->accumulators[i].value);
2077  }
2078 
2079  if (value->accumulators[i].value2 != NULL)
2080  {
2081  pr_free_value (value->accumulators[i].value2);
2082  }
2083  }
2084 
2085  db_private_free (thread_p, value->accumulators);
2086  }
2087 
2088  /* free tuple */
2089  value->first_tuple.size = 0;
2090  if (value->first_tuple.tpl != NULL)
2091  {
2092  db_private_free (thread_p, value->first_tuple.tpl);
2093  }
2094 
2095  /* free structure */
2096  db_private_free (thread_p, value);
2097 }
2098 
2099 /*
2100  * qdata_get_agg_hkey_size () - get aggregate hash key size
2101  * returns: size
2102  * key(in): hash key
2103  */
2104 int
2106 {
2107  int i, size = 0;
2108 
2109  for (i = 0; i < key->val_count; i++)
2110  {
2111  if (key->values[i] != NULL)
2112  {
2113  size += pr_value_mem_size (key->values[i]);
2114  }
2115  }
2116 
2117  return size + sizeof (aggregate_hash_key);
2118 }
2119 
2120 /*
2121  * qdata_get_agg_hvalue_size () - get aggregate hash value size
2122  * returns: size
2123  * value(in): hash
2124  * ret_delta(in): if false return actual size, if true return difference in
2125  * size between previously computed size and current size
2126  */
2127 int
2129 {
2130  int i, size = 0, old_size = 0;
2131 
2132  if (value->accumulators != NULL)
2133  {
2134  for (i = 0; i < value->func_count; i++)
2135  {
2136  if (value->accumulators[i].value != NULL)
2137  {
2138  size += pr_value_mem_size (value->accumulators[i].value);
2139  }
2140  if (value->accumulators[i].value2 != NULL)
2141  {
2142  size += pr_value_mem_size (value->accumulators[i].value2);
2143  }
2144  size += sizeof (cubxasl::aggregate_accumulator);
2145  }
2146  }
2147 
2148  size += sizeof (aggregate_hash_value);
2149  size += value->first_tuple.size;
2150 
2151  old_size = (ret_delta ? value->curr_size : 0);
2152  value->curr_size = size;
2153  size -= old_size;
2154 
2155  return size;
2156 }
2157 
2158 /*
2159  * qdata_free_agg_hentry () - free key-value pair of hash entry
2160  * returns: error code or NO_ERROR
2161  * key(in): key pointer
2162  * data(in): value pointer
2163  * args(in): args passed by mht_rem (should be null)
2164  */
2165 int
2166 qdata_free_agg_hentry (const void *key, void *data, void *args)
2167 {
2168  aggregate_hash_key *hkey = (aggregate_hash_key *) key;
2169  aggregate_hash_value *hvalue = (aggregate_hash_value *) data;
2170  cubthread::entry *thread_p = (cubthread::entry *) args;
2171 
2172  /* free key */
2173  qdata_free_agg_hkey (thread_p, hkey);
2174 
2175  /* free accumulators */
2176  qdata_free_agg_hvalue (thread_p, hvalue);
2177 
2178  /* all ok */
2179  return NO_ERROR;
2180 }
2181 
2182 /*
2183  * qdata_hash_agg_hkey () - compute hash of aggregate key
2184  * returns: hash value
2185  * key(in): key
2186  * ht_size(in): hash table size (in buckets)
2187  */
2188 unsigned int
2189 qdata_hash_agg_hkey (const void *key, unsigned int ht_size)
2190 {
2191  aggregate_hash_key *ckey = (aggregate_hash_key *) key;
2192  unsigned int hash_val = 0;
2193  int i;
2194 
2195  /* build hash value */
2196  for (i = 0; i < ckey->val_count; i++)
2197  {
2198  hash_val = hash_val ^ mht_get_hash_number (ht_size, ckey->values[i]);
2199  }
2200 
2201  return hash_val;
2202 }
2203 
2204 /*
2205  * qdata_agg_hkey_compare () - compare two aggregate keys
2206  * returns: comparison result
2207  * key1(in): first key
2208  * key2(in): second key
2209  * diff_pos(out): if not equal, position of difference, otherwise -1
2210  */
2213 {
2214  DB_VALUE_COMPARE_RESULT result;
2215  int i;
2216 
2217  assert (diff_pos);
2218  *diff_pos = -1;
2219 
2220  if (ckey1 == ckey2)
2221  {
2222  /* same pointer, same values */
2223  return DB_EQ;
2224  }
2225 
2226  if (ckey1->val_count != ckey2->val_count)
2227  {
2228  /* can't compare keys of different sizes; shouldn't get here */
2229  assert (false);
2230  return DB_UNK;
2231  }
2232 
2233  for (i = 0; i < ckey1->val_count; i++)
2234  {
2235  result = tp_value_compare (ckey1->values[i], ckey2->values[i], 0, 1);
2236  if (result != DB_EQ)
2237  {
2238  *diff_pos = i;
2239  return result;
2240  }
2241  }
2242 
2243  /* if we got this far, it's equal */
2244  return DB_EQ;
2245 }
2246 
2247 /*
2248  * qdata_agg_hkey_eq () - check equality of two aggregate keys
2249  * returns: true if equal, false otherwise
2250  * key1(in): first key
2251  * key2(in): second key
2252  */
2253 int
2254 qdata_agg_hkey_eq (const void *key1, const void *key2)
2255 {
2256  aggregate_hash_key *ckey1 = (aggregate_hash_key *) key1;
2257  aggregate_hash_key *ckey2 = (aggregate_hash_key *) key2;
2258  int decoy;
2259 
2260  /* compare for equality */
2261  return (qdata_agg_hkey_compare (ckey1, ckey2, &decoy) == DB_EQ);
2262 }
2263 
2264 /*
2265  * qdata_copy_agg_hkey () - deep copy aggregate key
2266  * returns: pointer to new aggregate hash key
2267  * thread_p(in): thread
2268  * key(in): source key
2269  */
2272 {
2273  aggregate_hash_key *new_key = NULL;
2274  int i = 0;
2275 
2276  if (key)
2277  {
2278  /* make a copy */
2279  new_key = qdata_alloc_agg_hkey (thread_p, key->val_count, false);
2280  }
2281 
2282  if (new_key)
2283  {
2284  /* copy values */
2285  new_key->val_count = key->val_count;
2286  for (i = 0; i < key->val_count; i++)
2287  {
2288  new_key->values[i] = pr_copy_value (key->values[i]);
2289  }
2290 
2291  new_key->free_values = true;
2292  }
2293 
2294  return new_key;
2295 }
2296 
2297 /*
2298  * qdata_load_agg_hvalue_in_agg_list () - load hash value in aggregate list
2299  * value(in): aggregate hash value
2300  * agg_list(in): aggregate list
2301  * copy_vals(in): true for deep copy of DB_VALUES, false for shallow copy
2302  */
2303 void
2305 {
2306  int i = 0;
2307  DB_TYPE db_type;
2308 
2309  if (value == NULL)
2310  {
2311  assert (false);
2312  return;
2313  }
2314 
2315  if (value->func_count != 0 && agg_list == NULL)
2316  {
2317  assert (false);
2318  return;
2319  }
2320 
2321  while (agg_list != NULL)
2322  {
2323  if (i >= value->func_count)
2324  {
2325  /* should not get here */
2326  assert (false);
2327  break;
2328  }
2329 
2330  if (agg_list->function != PT_GROUPBY_NUM)
2331  {
2332  if (copy_vals)
2333  {
2334  /* set tuple count */
2335  agg_list->accumulator.curr_cnt = value->accumulators[i].curr_cnt;
2336 
2337  /* copy */
2338  (void) pr_clone_value (value->accumulators[i].value, agg_list->accumulator.value);
2339  (void) pr_clone_value (value->accumulators[i].value2, agg_list->accumulator.value2);
2340  }
2341  else
2342  {
2343  /* set tuple count */
2344  agg_list->accumulator.curr_cnt = value->accumulators[i].curr_cnt;
2345 
2346  /*
2347  * shallow, fast copy dbval. This may be unsafe. Internally, value->accumulators[i].value and
2348  * agg_list->accumulator.value values keeps the same pointer to a buffer. If a value is cleared, the other
2349  * value refer a invalid memory. Probably a safety way would be to use clone.
2350  */
2351  * (agg_list->accumulator.value) = * (value->accumulators[i].value);
2352  * (agg_list->accumulator.value2) = * (value->accumulators[i].value2);
2353 
2354  /* reset accumulator values. */
2355  value->accumulators[i].value->need_clear = false;
2356  db_type = DB_VALUE_DOMAIN_TYPE (value->accumulators[i].value);
2357  if (db_type == DB_TYPE_VARCHAR || db_type == DB_TYPE_VARNCHAR)
2358  {
2360  }
2361 
2362  value->accumulators[i].value2->need_clear = false;
2363  db_type = DB_VALUE_DOMAIN_TYPE (value->accumulators[i].value2);
2364  if (db_type == DB_TYPE_VARCHAR || db_type == DB_TYPE_VARNCHAR)
2365  {
2367  }
2368  }
2369  }
2370 
2371  /* next */
2372  agg_list = agg_list->next;
2373  i++;
2374  }
2375 
2376  assert (i == value->func_count);
2377 }
2378 
2379 /*
2380  * qdata_save_agg_hentry_to_list () - save key/value pair in list file
2381  * returns: error code or NO_ERROR
2382  * thread_p(in): thread
2383  * key(in): group key
2384  * value(in): accumulators
2385  * temp_dbval_array(in): array of temporary values used for holding counters
2386  * list_id(in): target list file
2387  */
2388 int
2390  DB_VALUE *temp_dbval_array, qfile_list_id *list_id)
2391 {
2392  DB_VALUE tuple_count;
2393  int tuple_size = QFILE_TUPLE_LENGTH_SIZE;
2394  int col = 0, i;
2395  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
2396  int error = NO_ERROR;
2397 
2398  /* build tuple descriptor */
2399  for (i = 0; i < key->val_count; i++)
2400  {
2401  list_id->tpl_descr.f_valp[col++] = key->values[i];
2402  tuple_size += qdata_get_tuple_value_size_from_dbval (key->values[i]);
2403  }
2404 
2405  for (i = 0; i < value->func_count; i++)
2406  {
2407  list_id->tpl_descr.f_valp[col++] = value->accumulators[i].value;
2408  list_id->tpl_descr.f_valp[col++] = value->accumulators[i].value2;
2409 
2410  db_make_int (&temp_dbval_array[i], value->accumulators[i].curr_cnt);
2411  list_id->tpl_descr.f_valp[col++] = &temp_dbval_array[i];
2412 
2413  tuple_size += qdata_get_tuple_value_size_from_dbval (value->accumulators[i].value);
2414  tuple_size += qdata_get_tuple_value_size_from_dbval (value->accumulators[i].value2);
2415  tuple_size += qdata_get_tuple_value_size_from_dbval (&temp_dbval_array[i]);
2416  }
2417 
2418  db_make_int (&tuple_count, value->tuple_count);
2419  list_id->tpl_descr.f_valp[col++] = &tuple_count;
2420  tuple_size += qdata_get_tuple_value_size_from_dbval (&tuple_count);
2421 
2422  list_id->tpl_descr.tpl_size = tuple_size;
2423  /* add to list file */
2424  if (tuple_size <= QFILE_MAX_TUPLE_SIZE_IN_PAGE)
2425  {
2426  qfile_generate_tuple_into_list (thread_p, list_id, T_NORMAL);
2427  }
2428  else
2429  {
2430  error = qfile_copy_tuple_descr_to_tuple (thread_p, &list_id->tpl_descr, &tplrec);
2431  if (error != NO_ERROR)
2432  {
2433  goto cleanup;
2434  }
2435  error = qfile_add_tuple_to_list (thread_p, list_id, tplrec.tpl);
2436  if (error != NO_ERROR)
2437  {
2438  goto cleanup;
2439  }
2440  }
2441 
2442 cleanup:
2443  if (tplrec.tpl != NULL)
2444  {
2445  db_private_free (thread_p, tplrec.tpl);
2446  }
2447 
2448  /* all ok */
2449  return error;
2450 }
2451 
2452 /*
2453  * qdata_load_agg_hentry_from_tuple () - load key/value pair from list file
2454  * returns: error code or NO_ERROR
2455  * thread_p(in): thread
2456  * tuple(in): tuple to load from
2457  * key(out): group key
2458  * value(out): accumulators
2459  * list_id(in): list file
2460  * key_dom(in): key domains
2461  * acc_dom(in): accumulator domains
2462  */
2463 int
2465  aggregate_hash_value *value, tp_domain **key_dom,
2466  cubxasl::aggregate_accumulator_domain **acc_dom)
2467 {
2469  DB_VALUE int_val;
2470  OR_BUF iterator, buf;
2471  int i, rc;
2472 
2473  /* initialize buffer */
2474  db_make_int (&int_val, 0);
2475  OR_BUF_INIT (iterator, tuple, QFILE_GET_TUPLE_LENGTH (tuple));
2476  rc = or_advance (&iterator, QFILE_TUPLE_LENGTH_SIZE);
2477  if (rc != NO_ERROR)
2478  {
2479  return rc;
2480  }
2481 
2482  /* read key */
2483  for (i = 0; i < key->val_count; i++)
2484  {
2485  rc = qfile_locate_tuple_next_value (&iterator, &buf, &flag);
2486  if (rc != NO_ERROR)
2487  {
2488  return rc;
2489  }
2490 
2491  (void) pr_clear_value (key->values[i]);
2492  if (flag == V_BOUND)
2493  {
2494  key_dom[i]->type->data_readval (&buf, key->values[i], key_dom[i], -1, true, NULL, 0);
2495  }
2496  else
2497  {
2498  db_make_null (key->values[i]);
2499  }
2500  }
2501 
2502  /* read value */
2503  for (i = 0; i < value->func_count; i++)
2504  {
2505  /* read value */
2506  rc = qfile_locate_tuple_next_value (&iterator, &buf, &flag);
2507  if (rc != NO_ERROR)
2508  {
2509  return rc;
2510  }
2511 
2512  (void) pr_clear_value (value->accumulators[i].value);
2513  if (flag == V_BOUND)
2514  {
2515  acc_dom[i]->value_dom->type->data_readval (&buf, value->accumulators[i].value, acc_dom[i]->value_dom, -1,
2516  true, NULL, 0);
2517  }
2518  else
2519  {
2520  db_make_null (value->accumulators[i].value);
2521  }
2522 
2523  /* read value2 */
2524  rc = qfile_locate_tuple_next_value (&iterator, &buf, &flag);
2525  if (rc != NO_ERROR)
2526  {
2527  return rc;
2528  }
2529 
2530  (void) pr_clear_value (value->accumulators[i].value2);
2531  if (flag == V_BOUND)
2532  {
2533  acc_dom[i]->value2_dom->type->data_readval (&buf, value->accumulators[i].value2, acc_dom[i]->value2_dom, -1,
2534  true, NULL, 0);
2535  }
2536  else
2537  {
2538  db_make_null (value->accumulators[i].value2);
2539  }
2540 
2541  /* read tuple count */
2542  rc = qfile_locate_tuple_next_value (&iterator, &buf, &flag);
2543  if (rc != NO_ERROR)
2544  {
2545  return rc;
2546  }
2547 
2548  if (flag == V_BOUND)
2549  {
2550  tp_Integer_domain.type->data_readval (&buf, &int_val, &tp_Integer_domain, -1, true, NULL, 0);
2551  value->accumulators[i].curr_cnt = int_val.data.i;
2552  }
2553  else
2554  {
2555  /* should not happen */
2556  return ER_FAILED;
2557  }
2558  }
2559 
2560  /* read tuple count */
2561  rc = qfile_locate_tuple_next_value (&iterator, &buf, &flag);
2562  if (rc != NO_ERROR)
2563  {
2564  return rc;
2565  }
2566 
2567  if (flag == V_BOUND)
2568  {
2569  tp_Integer_domain.type->data_readval (&buf, &int_val, &tp_Integer_domain, -1, true, NULL, 0);
2570  value->tuple_count = int_val.data.i;
2571  }
2572  else
2573  {
2574  /* should not happen */
2575  return ER_FAILED;
2576  }
2577 
2578  /* all ok */
2579  return NO_ERROR;
2580 }
2581 
2582 /*
2583  * qdata_load_agg_hentry_from_list () - load key/value pair from list file
2584  * returns: error code or NO_ERROR
2585  * thread_p(in): thread
2586  * list_scan_id(in): list scan
2587  * key(out): group key
2588  * value(out): accumulators
2589  * key_dom(in): key domains
2590  * acc_dom(in): accumulator domains
2591  */
2592 SCAN_CODE
2594  aggregate_hash_value *value, tp_domain **key_dom,
2595  cubxasl::aggregate_accumulator_domain **acc_dom)
2596 {
2597  SCAN_CODE sc;
2598  QFILE_TUPLE_RECORD tuple_rec;
2599 
2600  sc = qfile_scan_list_next (thread_p, list_scan_id, &tuple_rec, PEEK);
2601  if (sc == S_SUCCESS)
2602  {
2603  if (qdata_load_agg_hentry_from_tuple (thread_p, tuple_rec.tpl, key, value, key_dom, acc_dom) != NO_ERROR)
2604  {
2605  return S_ERROR;
2606  }
2607  }
2608 
2609  return sc;
2610 }
2611 
2612 /*
2613  * qdata_save_agg_htable_to_list () - save aggregate hash table to list file
2614  * returns: error code or NO_ERROR
2615  * thread_p(in): thread
2616  * hash_table(in): take a wild guess
2617  * tuple_list_id(in): list file containing unsorted tuples
2618  * partial_list_id(in): list file containing partial accumulators
2619  * temp_dbval_array(in): array of temporary values used for holding counters
2620  *
2621  * NOTE: This function will clear the hash table!
2622  */
2623 int
2625  qfile_list_id *partial_list_id, db_value *temp_dbval_array)
2626 {
2627  aggregate_hash_key *key = NULL;
2628  aggregate_hash_value *value = NULL;
2629  HENTRY_PTR head;
2630  int rc;
2631 
2632  /* check nulls */
2633  if (hash_table == NULL || tuple_list_id == NULL || partial_list_id == NULL)
2634  {
2635  return ER_FAILED;
2636  }
2637 
2638  head = hash_table->act_head;
2639  while (head != NULL)
2640  {
2641  key = (aggregate_hash_key *) head->key;
2642  value = (aggregate_hash_value *) head->data;
2643 
2644  /* dump first tuple to unsorted list */
2645  if (value->first_tuple.tpl != NULL)
2646  {
2647  rc = qfile_add_tuple_to_list (thread_p, tuple_list_id, value->first_tuple.tpl);
2648  if (rc != NO_ERROR)
2649  {
2650  return rc;
2651  }
2652  }
2653 
2654  if (value->tuple_count > 0)
2655  {
2656  /* dump accumulators to partial list */
2657  rc = qdata_save_agg_hentry_to_list (thread_p, key, value, temp_dbval_array, partial_list_id);
2658  if (rc != NO_ERROR)
2659  {
2660  return rc;
2661  }
2662  }
2663 
2664  /* next */
2665  head = head->act_next;
2666  }
2667 
2668  /* clear hash table; memory will no longer be used */
2669  rc = mht_clear (hash_table, qdata_free_agg_hentry, (void *) thread_p);
2670  if (rc != NO_ERROR)
2671  {
2672  return rc;
2673  }
2674 
2675  /* all ok */
2676  return NO_ERROR;
2677 }
2678 
2679 /*
2680  * qdata_update_agg_interpolation_func_value_and_domain () -
2681  * return: NO_ERROR, or error code
2682  * agg_p(in): aggregate type
2683  * val(in):
2684  *
2685  */
2686 static int
2688 {
2689  int error = NO_ERROR;
2690  DB_TYPE dbval_type;
2691 
2692  assert (dbval != NULL && agg_p != NULL && QPROC_IS_INTERPOLATION_FUNC (agg_p) && agg_p->sort_list != NULL
2693  && agg_p->list_id != NULL && agg_p->list_id->type_list.type_cnt == 1);
2694 
2695  if (DB_IS_NULL (dbval))
2696  {
2697  goto end;
2698  }
2699 
2700  dbval_type = TP_DOMAIN_TYPE (agg_p->domain);
2701  if (dbval_type == DB_TYPE_VARIABLE || TP_DOMAIN_COLLATION_FLAG (agg_p->domain) != TP_DOMAIN_COLL_NORMAL)
2702  {
2703  dbval_type = DB_VALUE_DOMAIN_TYPE (dbval);
2704  agg_p->domain = tp_domain_resolve_default (dbval_type);
2705  }
2706 
2707  if (!TP_IS_DATE_OR_TIME_TYPE (dbval_type)
2708  && ((agg_p->function == PT_PERCENTILE_DISC && !TP_IS_NUMERIC_TYPE (dbval_type))
2709  || (agg_p->function != PT_PERCENTILE_DISC && dbval_type != DB_TYPE_DOUBLE)))
2710  {
2711  error = qdata_update_interpolation_func_value_and_domain (dbval, dbval, &agg_p->domain);
2712  if (error != NO_ERROR)
2713  {
2715 
2717  "DOUBLE, DATETIME, TIME");
2718  goto end;
2719  }
2720  }
2721  else
2722  {
2723  dbval_type = DB_VALUE_DOMAIN_TYPE (dbval);
2724  if (dbval_type != TP_DOMAIN_TYPE (agg_p->domain))
2725  {
2726  /* cast */
2727  error = db_value_coerce (dbval, dbval, agg_p->domain);
2728  if (error != NO_ERROR)
2729  {
2730  goto end;
2731  }
2732  }
2733  }
2734 
2735  /* set list_id domain, if it's not set */
2736  if (TP_DOMAIN_TYPE (agg_p->list_id->type_list.domp[0]) != TP_DOMAIN_TYPE (agg_p->domain))
2737  {
2738  agg_p->list_id->type_list.domp[0] = agg_p->domain;
2739  agg_p->sort_list->pos_descr.dom = agg_p->domain;
2740  }
2741 
2742 end:
2743 
2744  return error;
2745 }
2746 
2747 /*
2748  * qdata_group_concat_first_value() - concatenates the first value
2749  * return: NO_ERROR, or ER_code
2750  * thread_p(in) :
2751  * agg_p(in) : GROUP_CONCAT aggregate
2752  * dbvalue(in) : current value
2753  */
2754 int
2756 {
2757  TP_DOMAIN *result_domain;
2758  DB_TYPE agg_type;
2759  int max_allowed_size;
2760  DB_VALUE tmp_val;
2761  int error_code = NO_ERROR;
2762 
2763  db_make_null (&tmp_val);
2764 
2765  agg_type = DB_VALUE_DOMAIN_TYPE (agg_p->accumulator.value);
2766  /* init the aggregate value domain */
2768  if (error_code != NO_ERROR)
2769  {
2770  ASSERT_ERROR ();
2771  pr_clear_value (dbvalue);
2772  return error_code;
2773  }
2774 
2776  TP_DOMAIN_CODESET (agg_p->domain),
2777  TP_DOMAIN_COLLATION (agg_p->domain));
2778  if (error_code != NO_ERROR)
2779  {
2780  ASSERT_ERROR ();
2781  return error_code;
2782  }
2783 
2785  {
2787  }
2788 
2789  /* concat the first value */
2790  result_domain = ((TP_DOMAIN_TYPE (agg_p->domain) == agg_type) ? agg_p->domain : NULL);
2791 
2792  max_allowed_size = (int) prm_get_bigint_value (PRM_ID_GROUP_CONCAT_MAX_LEN);
2793 
2794  error_code = qdata_concatenate_dbval (thread_p, agg_p->accumulator.value, dbvalue, &tmp_val, result_domain,
2795  max_allowed_size, "GROUP_CONCAT()");
2796  if (error_code != NO_ERROR)
2797  {
2798  ASSERT_ERROR ();
2799  pr_clear_value (dbvalue);
2800  return error_code;
2801  }
2802 
2803  /* check for concat success */
2804  if (!DB_IS_NULL (&tmp_val))
2805  {
2806  (void) pr_clear_value (agg_p->accumulator.value);
2807  pr_clone_value (&tmp_val, agg_p->accumulator.value);
2808  }
2809 
2810  (void) pr_clear_value (&tmp_val);
2811 
2812  return NO_ERROR;
2813 }
2814 
2815 /*
2816  * qdata_group_concat_value() - concatenates a value
2817  * return: NO_ERROR, or ER_code
2818  * thread_p(in) :
2819  * agg_p(in) : GROUP_CONCAT aggregate
2820  * dbvalue(in) : current value
2821  */
2822 int
2824 {
2825  TP_DOMAIN *result_domain;
2826  DB_TYPE agg_type;
2827  int max_allowed_size;
2828  DB_VALUE tmp_val;
2829 
2830  db_make_null (&tmp_val);
2831 
2832  agg_type = DB_VALUE_DOMAIN_TYPE (agg_p->accumulator.value);
2833 
2834  result_domain = ((TP_DOMAIN_TYPE (agg_p->domain) == agg_type) ? agg_p->domain : NULL);
2835 
2836  max_allowed_size = (int) prm_get_bigint_value (PRM_ID_GROUP_CONCAT_MAX_LEN);
2837 
2839  {
2841  TP_DOMAIN_CODESET (agg_p->domain),
2842  TP_DOMAIN_COLLATION (agg_p->domain)) != NO_ERROR)
2843  {
2844  return ER_FAILED;
2845  }
2847  }
2848 
2849  /* add separator if specified (it may be the case for bit string) */
2850  if (!DB_IS_NULL (agg_p->accumulator.value2))
2851  {
2852  if (qdata_concatenate_dbval (thread_p, agg_p->accumulator.value, agg_p->accumulator.value2, &tmp_val,
2853  result_domain, max_allowed_size, "GROUP_CONCAT()") != NO_ERROR)
2854  {
2855  return ER_FAILED;
2856  }
2857 
2858  /* check for concat success */
2859  if (!DB_IS_NULL (&tmp_val))
2860  {
2861  (void) pr_clear_value (agg_p->accumulator.value);
2862  pr_clone_value (&tmp_val, agg_p->accumulator.value);
2863  }
2864  }
2865  else
2866  {
2867  assert (agg_type == DB_TYPE_VARBIT || agg_type == DB_TYPE_BIT);
2868  }
2869 
2870  pr_clear_value (&tmp_val);
2871 
2872  if (qdata_concatenate_dbval (thread_p, agg_p->accumulator.value, dbvalue, &tmp_val, result_domain, max_allowed_size,
2873  "GROUP_CONCAT()") != NO_ERROR)
2874  {
2875  pr_clear_value (dbvalue);
2876  return ER_FAILED;
2877  }
2878 
2879  /* check for concat success */
2880  if (!DB_IS_NULL (&tmp_val))
2881  {
2882  (void) pr_clear_value (agg_p->accumulator.value);
2883  pr_clone_value (&tmp_val, agg_p->accumulator.value);
2884  }
2885 
2886  pr_clear_value (&tmp_val);
2887 
2888  return NO_ERROR;
2889 }
2890 
2891 static int
2893  QFILE_LIST_SCAN_ID *scan_id)
2894 {
2895  int error = NO_ERROR;
2896  int tuple_count;
2897  double row_num_d, f_row_num_d, c_row_num_d, percentile_d;
2898  FUNC_TYPE function;
2899  double cur_group_percentile;
2900 
2901  assert (agg_p != NULL && scan_id != NULL && scan_id->status == S_OPENED);
2903 
2904  function = agg_p->function;
2905  cur_group_percentile = agg_p->info.percentile.cur_group_percentile;
2906 
2907  tuple_count = scan_id->list_id.tuple_cnt;
2908  if (tuple_count < 1)
2909  {
2910  return NO_ERROR;
2911  }
2912 
2913  if (function == PT_MEDIAN)
2914  {
2915  percentile_d = 0.5;
2916  }
2917  else
2918  {
2919  percentile_d = cur_group_percentile;
2920 
2921  if (function == PT_PERCENTILE_DISC)
2922  {
2923  percentile_d = ceil (percentile_d * tuple_count) / tuple_count;
2924  }
2925  }
2926 
2927  row_num_d = ((double) (tuple_count - 1)) * percentile_d;
2928  f_row_num_d = floor (row_num_d);
2929 
2930  if (function == PT_PERCENTILE_DISC)
2931  {
2932  c_row_num_d = f_row_num_d;
2933  }
2934  else
2935  {
2936  c_row_num_d = ceil (row_num_d);
2937  }
2938 
2939  error =
2940  qdata_get_interpolation_function_result (thread_p, scan_id, scan_id->list_id.type_list.domp[0], 0, row_num_d,
2941  f_row_num_d, c_row_num_d, agg_p->accumulator.value, &agg_p->domain,
2942  agg_p->function);
2943 
2944  if (error == NO_ERROR)
2945  {
2946  agg_p->opr_dbtype = TP_DOMAIN_TYPE (agg_p->domain);
2947  }
2948 
2949  return error;
2950 }
#define QFILE_TUPLE_VALUE_HEADER_SIZE
Definition: query_list.h:229
aggregate_hash_key * qdata_copy_agg_hkey(cubthread::entry *thread_p, aggregate_hash_key *key)
HENTRY_PTR act_next
Definition: memory_hash.h:44
int qfile_generate_tuple_into_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, QFILE_TUPLE_TYPE tuple_type)
Definition: list_file.c:1749
int data_readval(struct or_buf *buf, DB_VALUE *value, const tp_domain *domain, int size, bool copy, char *copy_buf, int copy_buf_len) const
aggregate_hash_value * qdata_alloc_agg_hvalue(cubthread::entry *thread_p, int func_cnt, cubxasl::aggregate_list_node *g_agg_list)
#define TP_IS_DATE_OR_TIME_TYPE(typeid)
TP_DOMAIN_STATUS tp_value_coerce(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain)
int db_make_json(DB_VALUE *value, JSON_DOC *json_document, bool need_clear)
int db_value_coerce(const DB_VALUE *src, DB_VALUE *dest, const DB_DOMAIN *desired_domain)
Definition: db_macro.c:1779
#define NO_ERROR
Definition: error_code.h:46
aggregate_specific_function_info info
int db_evaluate_json_merge_preserve(DB_VALUE *result, DB_VALUE *const *arg, const int num_args)
Definition: arithmetic.c:6163
int pr_data_writeval_disk_size(DB_VALUE *value)
int mht_clear(MHT_TABLE *ht, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1180
SORT_NULLS
Definition: query_list.h:404
DB_VALUE_COMPARE_RESULT tp_value_compare(const DB_VALUE *value1, const DB_VALUE *value2, int allow_coercion, int total_order)
#define ASSERT_ERROR()
SCAN_CODE
DB_VALUE * pr_make_value(void)
QFILE_TUPLE_VALUE_TYPE_LIST type_list
Definition: query_list.h:428
int qdata_bit_xor_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
int data_writeval(struct or_buf *buf, const DB_VALUE *value) const
#define QFILE_FREE_AND_INIT_LIST_ID(list_id)
Definition: list_file.h:56
#define ER_TF_BUFFER_OVERFLOW
Definition: error_code.h:388
unsigned int qdata_hash_agg_hkey(const void *key, unsigned int ht_size)
int db_make_bigint(DB_VALUE *value, const DB_BIGINT num)
int db_get_int(const DB_VALUE *value)
int qdata_get_tuple_value_size_from_dbval(DB_VALUE *dbval_p)
DB_TYPE
Definition: dbtype_def.h:670
DB_C_DOUBLE db_get_double(const DB_VALUE *value)
#define ER_FAILED
Definition: error_code.h:47
REGU_VARIABLE_LIST next
Definition: regu_var.hpp:221
void qdata_free_agg_hvalue(cubthread::entry *thread_p, aggregate_hash_value *value)
#define ER_PERCENTILE_FUNC_INVALID_PERCENTILE_RANGE
Definition: error_code.h:1505
SCAN_CODE qfile_scan_list_next(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p, QFILE_TUPLE_RECORD *tuple_record_p, int peek)
Definition: list_file.c:4724
int db_string_fix_string_size(DB_VALUE *src_string)
int qdata_evaluate_aggregate_optimize(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_p, HFID *hfid_p, OID *super_oid)
#define OR_BUF_INIT(buf, data, size)
#define ER_QPROC_INVALID_XASLNODE
Definition: error_code.h:532
#define ASSERT_ERROR_AND_SET(error_code)
int fetch_copy_dbval(THREAD_ENTRY *thread_p, REGU_VARIABLE *regu_var, val_descr *vd, OID *class_oid, OID *obj_oid, QFILE_TUPLE tpl, DB_VALUE *dbval)
Definition: fetch.c:4466
int qfile_locate_tuple_next_value(OR_BUF *iterator, OR_BUF *buf, QFILE_TUPLE_VALUE_FLAG *flag)
Definition: list_file.c:952
FUNC_TYPE
DB_VALUE_COMPARE_RESULT cmpval(const DB_VALUE *value, const DB_VALUE *value2, int do_coercion, int total_order, int *start_colp, int collation) const
int db_accumulate_json_arrayagg(const DB_VALUE *json_db_val, DB_VALUE *json_res)
Definition: arithmetic.c:5383
int qdata_agg_hkey_eq(const void *key1, const void *key2)
aggregate_hash_key * qdata_alloc_agg_hkey(cubthread::entry *thread_p, int val_cnt, bool alloc_vals)
bool REGU_VARIABLE_IS_FLAGED(const regu_variable_node *regu, int flag)
Definition: regu_var.hpp:253
aggregate_accumulator accumulator
int qdata_update_interpolation_func_value_and_domain(DB_VALUE *src_val, DB_VALUE *dest_val, TP_DOMAIN **domain)
TP_DOMAIN tp_Integer_domain
int er_errid(void)
int btree_find_min_or_max_key(THREAD_ENTRY *thread_p, BTID *btid, DB_VALUE *key, int find_min_key)
Definition: btree.c:16284
int qdata_save_agg_hentry_to_list(cubthread::entry *thread_p, aggregate_hash_key *key, aggregate_hash_value *value, DB_VALUE *temp_dbval_array, qfile_list_id *list_id)
#define QPROC_IS_INTERPOLATION_FUNC(func_p)
Definition: xasl.h:531
SORT_ORDER
Definition: query_list.h:398
QFILE_TUPLE_DESCRIPTOR tpl_descr
Definition: query_list.h:441
enum tp_domain_status TP_DOMAIN_STATUS
int qdata_subtract_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
HL_HEAPID db_change_private_heap(THREAD_ENTRY *thread_p, HL_HEAPID heap_id)
Definition: memory_alloc.c:337
int qdata_bit_and_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
int qdata_evaluate_aggregate_hierarchy(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_p, HFID *root_hfid, BTID *root_btid, hierarchy_aggregate_helper *helper)
SORT_ORDER s_order
Definition: query_list.h:417
int db_string_make_empty_typed_string(DB_VALUE *db_val, const DB_TYPE db_type, int precision, int codeset, int collation_id)
DB_DOMAIN_INFO domain
Definition: dbtype_def.h:1082
int qdata_get_agg_hvalue_size(aggregate_hash_value *value, bool ret_delta)
int qdata_multiply_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
void THREAD_ENTRY
void qdata_free_agg_hkey(cubthread::entry *thread_p, aggregate_hash_key *key)
int qdata_divide_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
UINT64 prm_get_bigint_value(PARAM_ID prm_id)
#define QFILE_GET_TUPLE_VALUE_FLAG(ptr)
Definition: query_list.h:250
DB_DATA data
Definition: dbtype_def.h:1083
#define QFILE_MAX_TUPLE_SIZE_IN_PAGE
Definition: query_list.h:217
PR_TYPE * pr_type_from_id(DB_TYPE id)
int pr_free_value(DB_VALUE *value)
TP_DOMAIN * tp_domain_resolve_default(DB_TYPE type)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define assert(x)
int32_t fileid
Definition: dbtype_def.h:886
void pr_clear_value_vector(std::vector< DB_VALUE > &value_vector)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
struct db_char::@52 info
void qfile_destroy_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:2163
struct sort_list * next
Definition: query_list.h:415
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
int qdata_finalize_aggregate_list(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_list_p, bool keep_list_file)
REGU_VARIABLE value
Definition: regu_var.hpp:222
const int REGU_VARIABLE_CLEAR_AT_CLONE_DECACHE
Definition: regu_var.hpp:165
int qdata_load_agg_hentry_from_tuple(cubthread::entry *thread_p, QFILE_TUPLE tuple, aggregate_hash_key *key, aggregate_hash_value *value, tp_domain **key_dom, cubxasl::aggregate_accumulator_domain **acc_dom)
int fetch_peek_dbval(THREAD_ENTRY *thread_p, REGU_VARIABLE *regu_var, val_descr *vd, OID *class_oid, OID *obj_oid, QFILE_TUPLE tpl, DB_VALUE **peek_dbval)
Definition: fetch.c:3773
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
regu_variable_node * percentile_reguvar
#define TP_DOMAIN_COLLATION(dom)
#define TP_IS_NUMERIC_TYPE(typeid)
int qdata_aggregate_accumulator_to_accumulator(cubthread::entry *thread_p, cubxasl::aggregate_accumulator *acc, cubxasl::aggregate_accumulator_domain *acc_dom, FUNC_TYPE func_type, tp_domain *func_domain, cubxasl::aggregate_accumulator *new_acc)
int qdata_get_interpolation_function_result(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id, tp_domain *domain, int pos, double row_num_d, double f_row_num_d, double c_row_num_d, DB_VALUE *result, tp_domain **result_dom, FUNC_TYPE function)
#define ER_PERCENTILE_FUNC_PERCENTILE_CHANGED_IN_GROUP
Definition: error_code.h:1506
int qdata_get_agg_hkey_size(aggregate_hash_key *key)
TP_DOMAIN_STATUS tp_value_cast(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain, bool implicit_coercion)
VFID vfid
#define TP_DOMAIN_TYPE(dom)
static void cleanup(int signo)
Definition: broker.c:717
#define QFILE_GET_TUPLE_VALUE_LENGTH(ptr)
Definition: query_list.h:253
DB_VALUE * pr_copy_value(DB_VALUE *value)
#define NULL
Definition: freelistheap.h:34
static int qdata_group_concat_value(THREAD_ENTRY *thread_p, AGGREGATE_TYPE *agg_p, DB_VALUE *dbvalue)
#define QFILE_TUPLE_LENGTH_SIZE
Definition: query_list.h:224
static int qdata_group_concat_first_value(THREAD_ENTRY *thread_p, AGGREGATE_TYPE *agg_p, DB_VALUE *dbvalue)
struct pr_type * type
Definition: object_domain.h:76
static int qdata_process_distinct_or_sort(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_p, QUERY_ID query_id)
DB_CHAR ch
Definition: dbtype_def.h:1070
#define QFILE_GET_TUPLE_LENGTH(tpl)
Definition: query_list.h:238
void * data
Definition: memory_hash.h:50
int qdata_add_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: query_list.h:416
aggregate_list_node * next
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
void or_init(OR_BUF *buf, char *data, int length)
HENTRY_PTR act_head
Definition: memory_hash.h:61
int btree_get_unique_statistics_for_count(THREAD_ENTRY *thread_p, BTID *btid, int *oid_cnt, int *null_cnt, int *key_cnt)
Definition: btree.c:6171
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
need_clear_type need_clear
Definition: dbtype_def.h:1084
int qdata_evaluate_aggregate_list(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_list_p, val_descr *val_desc_p, cubxasl::aggregate_accumulator *alt_acc_list)
#define cmp
Definition: mprec.h:351
int pr_clear_value(DB_VALUE *value)
int qfile_open_list_scan(QFILE_LIST_ID *list_id_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4658
int qdata_bit_or_dbval(DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p)
#define ER_JSON_OBJECT_NAME_IS_NULL
Definition: error_code.h:1550
DB_VALUE_COMPARE_RESULT qdata_agg_hkey_compare(aggregate_hash_key *ckey1, aggregate_hash_key *ckey2, int *diff_pos)
SCAN_CODE qdata_load_agg_hentry_from_list(cubthread::entry *thread_p, qfile_list_scan_id *list_scan_id, aggregate_hash_key *key, aggregate_hash_value *value, tp_domain **key_dom, cubxasl::aggregate_accumulator_domain **acc_dom)
#define DB_DEFAULT_SCALE
Definition: dbtype_def.h:561
struct db_domain_info::general_info general_info
int64_t DB_BIGINT
Definition: dbtype_def.h:751
static int qdata_aggregate_multiple_values_to_accumulator(cubthread::entry *thread_p, cubxasl::aggregate_accumulator *acc, cubxasl::aggregate_accumulator_domain *domain, FUNC_TYPE func_type, tp_domain *func_domain, std::vector< DB_VALUE > &db_values)
static void error(const char *msg)
Definition: gencat.c:331
static int rc
Definition: serial.c:50
#define DB_DEFAULT_PRECISION
Definition: dbtype_def.h:558
void qfile_close_scan(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4774
unsigned char compressed_need_clear
Definition: dbtype_def.h:982
#define ARG_FILE_LINE
Definition: error_manager.h:44
unsigned int mht_get_hash_number(const int ht_size, const DB_VALUE *val)
Definition: memory_hash.c:2275
static int qdata_aggregate_interpolation(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_p, QFILE_LIST_SCAN_ID *scan_id)
bool er_has_error(void)
QFILE_LIST_ID list_id
Definition: query_list.h:507
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
QFILE_TUPLE_VALUE_FLAG
Definition: query_list.h:291
cubxasl::aggregate_accumulator * accumulators
int qfile_add_item_to_list(THREAD_ENTRY *thread_p, char *item_p, int item_size, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:2330
static int qdata_calculate_aggregate_cume_dist_percent_rank(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_p, VAL_DESCR *val_desc_p)
#define BTID_COPY(btid_ptr1, btid_ptr2)
static int qdata_update_agg_interpolation_func_value_and_domain(cubxasl::aggregate_list_node *agg_p, DB_VALUE *val)
const void * key
Definition: memory_hash.h:49
SCAN_STATUS status
Definition: query_list.h:498
int qfile_copy_tuple_descr_to_tuple(THREAD_ENTRY *thread_p, QFILE_TUPLE_DESCRIPTOR *tpl_descr, QFILE_TUPLE_RECORD *tplrec)
Definition: list_file.c:2846
char * QFILE_TUPLE
Definition: query_list.h:281
bool prm_get_bool_value(PARAM_ID prm_id)
int qfile_copy_list_id(QFILE_LIST_ID *dest_list_id_p, const QFILE_LIST_ID *src_list_id_p, bool is_include_sort_list)
Definition: list_file.c:433
int pr_value_mem_size(const DB_VALUE *value)
QFILE_LIST_ID * qfile_open_list(THREAD_ENTRY *thread_p, QFILE_TUPLE_VALUE_TYPE_LIST *type_list_p, SORT_LIST *sort_list_p, QUERY_ID query_id, int flag)
Definition: list_file.c:1142
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
int i
Definition: dynamic_load.c:954
int db_make_null(DB_VALUE *value)
QFILE_LIST_ID * qfile_sort_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, SORT_LIST *sort_list_p, QUERY_OPTIONS option, bool do_close)
Definition: list_file.c:4030
void qfile_close_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:1263
#define DB_IS_NULL(value)
Definition: dbtype.h:63
int db_make_double(DB_VALUE *value, const DB_C_DOUBLE num)
static int qdata_aggregate_value_to_accumulator(cubthread::entry *thread_p, cubxasl::aggregate_accumulator *acc, cubxasl::aggregate_accumulator_domain *domain, FUNC_TYPE func_type, tp_domain *func_domain, db_value *value, bool is_acc_to_acc)
#define ER_ARG_CAN_NOT_BE_CASTED_TO_DESIRED_DOMAIN
Definition: error_code.h:1419
#define BTID_IS_NULL(btid)
int setval(DB_VALUE *dest, const DB_VALUE *src, bool copy) const
int db_make_int(DB_VALUE *value, const int num)
void qdata_load_agg_hvalue_in_agg_list(aggregate_hash_value *value, cubxasl::aggregate_list_node *agg_list, bool copy_vals)
int qdata_free_agg_hentry(const void *key, void *data, void *args)
SORT_NULLS s_nulls
Definition: query_list.h:418
#define TP_DOMAIN_CODESET(dom)
int db_accumulate_json_objectagg(const DB_VALUE *json_key, const DB_VALUE *json_db_val, DB_VALUE *json_res)
Definition: arithmetic.c:5437
int qdata_save_agg_htable_to_list(cubthread::entry *thread_p, mht_table *hash_table, qfile_list_id *tuple_list_id, qfile_list_id *partial_list_id, db_value *temp_dbval_array)
#define ER_QPROC_INVALID_DATATYPE
Definition: error_code.h:534
int qdata_initialize_aggregate_list(cubthread::entry *thread_p, cubxasl::aggregate_list_node *agg_list_p, QUERY_ID query_id)
DB_VALUE_COMPARE_RESULT
Definition: dbtype_def.h:199
#define PEEK
Definition: file_io.h:74
JSON_DOC * db_json_allocate_doc()
Definition: db_json.cpp:2332
int or_advance(OR_BUF *buf, int offset)
const char * fcode_get_uppercase_name(FUNC_TYPE ftype)
regu_variable_list_node * operands
DB_VALUE * db_values
Definition: esql_cli.c:356
int db_value_domain_init(DB_VALUE *value, const DB_TYPE type, const int precision, const int scale)
Definition: db_macro.c:153
#define TP_DOMAIN_COLLATION_FLAG(dom)
int qdata_concatenate_dbval(THREAD_ENTRY *thread_p, DB_VALUE *dbval1_p, DB_VALUE *dbval2_p, DB_VALUE *result_p, tp_domain *domain_p, const int max_allowed_size, const char *warning_context)
int qfile_add_tuple_to_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p, QFILE_TUPLE tuple)
Definition: list_file.c:1511