LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_datetrunc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 51 139 36.7 %
Date: 2024-10-03 20:03:20 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "sql.h"
      15             : #include "mal_instruction.h"
      16             : 
      17             : #define do_date_trunc(val, DIVISOR)                                     \
      18             :         timestamp_create(timestamp_date(val),                           \
      19             :                          (timestamp_daytime(val) / (DIVISOR)) * (DIVISOR))
      20             : 
      21             : #define date_trunc_time_loop(NAME, DIVISOR)                             \
      22             :         do {                                                            \
      23             :                 if  ( strcasecmp(*scale, NAME) == 0){                   \
      24             :                         for( ; lo < hi; lo++)                                \
      25             :                                 if (is_timestamp_nil(bt[lo])) {         \
      26             :                                         dt[lo] = timestamp_nil;         \
      27             :                                 } else {                                \
      28             :                                         dt[lo] = do_date_trunc(bt[lo], DIVISOR); \
      29             :                                 }                                       \
      30             :                 }                                                       \
      31             :         } while (0)
      32             : 
      33             : static inline bool
      34          78 : truncate_check(const char *scale)
      35             : {
      36          78 :         return
      37         149 :                 strcasecmp(scale, "millennium") == 0 ||
      38          71 :                 strcasecmp(scale, "century") == 0  ||
      39          61 :                 strcasecmp(scale, "decade") == 0 ||
      40          53 :                 strcasecmp(scale, "year") == 0 ||
      41          48 :                 strcasecmp(scale, "quarter" ) == 0 ||
      42          43 :                 strcasecmp(scale, "month") == 0 ||
      43          37 :                 strcasecmp(scale, "week") == 0 ||
      44          30 :                 strcasecmp(scale, "day") == 0  ||
      45          25 :                 strcasecmp(scale, "hour") == 0 ||
      46          20 :                 strcasecmp(scale, "minute") == 0 ||
      47          15 :                 strcasecmp(scale, "second") == 0 ||
      48          88 :                 strcasecmp(scale, "milliseconds") == 0 ||
      49           5 :                 strcasecmp(scale, "microseconds") == 0;
      50             : }
      51             : 
      52             : str
      53           0 : bat_date_trunc(bat *res, const str *scale, const bat *bid)
      54             : {
      55           0 :         BAT *b, *bn;
      56           0 :         oid lo, hi;
      57           0 :         const timestamp *bt;
      58           0 :         timestamp *dt;
      59           0 :         char *msg = NULL;
      60           0 :         date days;
      61             : 
      62           0 :         if ( truncate_check(*scale) == 0)
      63           0 :                 throw(SQL, "batcalc.truncate_timestamp", SQLSTATE(HY005) "Improper directive ");
      64             : 
      65           0 :         if ((b = BATdescriptor(*bid)) == NULL) {
      66           0 :                 throw(SQL, "batcalc.truncate_timestamp", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
      67             :         }
      68           0 :         bn = COLnew(b->hseqbase, TYPE_timestamp, BATcount(b), TRANSIENT);
      69           0 :         if (bn == NULL) {
      70           0 :                 BBPunfix(b->batCacheid);
      71           0 :                 throw(SQL, "sql.truncate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      72             :         }
      73             : 
      74           0 :         BATiter bi = bat_iterator(b);
      75           0 :         bt = (const timestamp *) bi.base;
      76           0 :         dt = (timestamp *) Tloc(bn, 0);
      77             : 
      78           0 :         lo = 0;
      79           0 :         hi = lo + BATcount(b);
      80             : 
      81           0 :         date_trunc_time_loop("microseconds", 1);
      82           0 :         date_trunc_time_loop("milliseconds", 1000);
      83           0 :         date_trunc_time_loop("second", 1000000);
      84           0 :         date_trunc_time_loop("minute", 1000000 * 60);
      85           0 :         date_trunc_time_loop("hour", LL_CONSTANT(1000000) * 60 * 60);
      86             : 
      87           0 :         if  ( strcasecmp(*scale, "day") == 0){
      88           0 :                 for( ; lo < hi; lo++)
      89           0 :                         if (is_timestamp_nil(bt[lo])) {
      90           0 :                                 dt[lo] = timestamp_nil;
      91             :                         } else {
      92           0 :                                 days = timestamp_date(bt[lo]);
      93           0 :                                 dt[lo] = timestamp_fromdate(days);
      94             :                         }
      95             :         }
      96             : 
      97           0 :         if  ( strcasecmp(*scale, "week") == 0){
      98           0 :                 for( ; lo < hi; lo++)
      99           0 :                         if (is_timestamp_nil(bt[lo])) {
     100           0 :                                 dt[lo] = timestamp_nil;
     101             :                         } else {
     102           0 :                                 days = timestamp_date(bt[lo]);
     103           0 :                                 dt[lo] = timestamp_fromdate(date_add_day(days, 1 - date_dayofweek(days)));
     104             :                         }
     105             :         }
     106             : 
     107           0 :         if  ( strcasecmp(*scale, "month") == 0){
     108           0 :                 for( ; lo < hi; lo++)
     109           0 :                         if (is_timestamp_nil(bt[lo])) {
     110           0 :                                 dt[lo] = timestamp_nil;
     111             :                         } else {
     112           0 :                                 days = timestamp_date(bt[lo]);
     113           0 :                                 dt[lo] = timestamp_fromdate(
     114             :                                         date_create(date_year(days),
     115           0 :                                                     date_month(days),
     116             :                                                     1));
     117             :                         }
     118             :         }
     119             : 
     120           0 :         if  ( strcasecmp(*scale, "quarter") == 0){
     121           0 :                 for( ; lo < hi; lo++)
     122           0 :                         if (is_timestamp_nil(bt[lo])) {
     123           0 :                                 dt[lo] = timestamp_nil;
     124             :                         } else {
     125           0 :                                 days = timestamp_date(bt[lo]);
     126           0 :                                 dt[lo] = timestamp_fromdate(
     127             :                                         date_create(date_year(days),
     128           0 :                                                     ((date_month(days) - 1) / 3) * 3 + 1,
     129             :                                                     1));
     130             :                         }
     131             :         }
     132             : 
     133           0 :         if  ( strcasecmp(*scale, "year") == 0){
     134           0 :                 for( ; lo < hi; lo++)
     135           0 :                         if (is_timestamp_nil(bt[lo])) {
     136           0 :                                 dt[lo] = timestamp_nil;
     137             :                         } else {
     138           0 :                                 days = timestamp_date(bt[lo]);
     139           0 :                                 dt[lo] = timestamp_fromdate(date_create(date_year(days), 1, 1));
     140             :                         }
     141             :         }
     142             : 
     143           0 :         if  ( strcasecmp(*scale, "decade") == 0){
     144           0 :                 for( ; lo < hi; lo++)
     145           0 :                         if (is_timestamp_nil(bt[lo])) {
     146           0 :                                 dt[lo] = timestamp_nil;
     147             :                         } else {
     148           0 :                                 days = timestamp_date(bt[lo]);
     149           0 :                                 dt[lo] = timestamp_fromdate(date_create((date_year(days) / 10) * 10, 1, 1));
     150             :                         }
     151             :         }
     152             : 
     153           0 :         if  ( strcasecmp(*scale, "century") == 0){
     154           0 :                 for( ; lo < hi; lo++)
     155           0 :                         if (is_timestamp_nil(bt[lo])) {
     156           0 :                                 dt[lo] = timestamp_nil;
     157             :                         } else {
     158           0 :                                 days = timestamp_date(bt[lo]);
     159           0 :                                 dt[lo] = timestamp_fromdate(date_create((date_year(days) / 100) * 100, 1, 1));
     160             :                         }
     161             :         }
     162             : 
     163           0 :         if  ( strcasecmp(*scale, "millennium") == 0){
     164           0 :                 for( ; lo < hi; lo++)
     165           0 :                         if (is_timestamp_nil(bt[lo])) {
     166           0 :                                 dt[lo] = timestamp_nil;
     167             :                         } else {
     168           0 :                                 days = timestamp_date(bt[lo]);
     169           0 :                                 dt[lo] = timestamp_fromdate(date_create((date_year(days) / 1000) * 1000, 1, 1));
     170             :                         }
     171             :         }
     172             : 
     173           0 :         bool btnonil = bi.nonil, btnil = bi.nil, btsorted = bi.sorted, btrevsorted = bi.revsorted;
     174           0 :         bat_iterator_end(&bi);
     175           0 :         BBPunfix(b->batCacheid);
     176           0 :         BATsetcount(bn, (BUN) lo);
     177             :         /* we can inherit most properties */
     178           0 :         bn->tnonil = btnonil;
     179           0 :         bn->tnil = btnil;
     180           0 :         bn->tsorted = btsorted;
     181           0 :         bn->trevsorted = btrevsorted;
     182           0 :         bn->tkey = false;    /* can't be sure */
     183           0 :         *res = bn->batCacheid;
     184           0 :         BBPkeepref(bn);
     185           0 :         return msg;
     186             : }
     187             : 
     188             : #define date_trunc_single_time(NAME, DIVISOR)                   \
     189             :         do {                                                    \
     190             :                 if  ( strcasecmp(*scale, NAME) == 0){           \
     191             :                         *dt = do_date_trunc(*bt, DIVISOR);      \
     192             :                 }                                               \
     193             :         } while (0)
     194             : 
     195             : str
     196          78 : date_trunc(timestamp *dt, const str *scale, const timestamp *bt)
     197             : {
     198          78 :         str msg = MAL_SUCCEED;
     199          78 :         date days;
     200             : 
     201          78 :         if (truncate_check(*scale) == 0)
     202           0 :                 throw(SQL, "sql.truncate", SQLSTATE(HY013) "Improper directive ");
     203             : 
     204          78 :         if (is_timestamp_nil(*bt)) {
     205          13 :                 *dt = timestamp_nil;
     206          13 :                 return MAL_SUCCEED;
     207             :         }
     208             : 
     209          65 :         date_trunc_single_time("microseconds", 1);
     210          65 :         date_trunc_single_time("milliseconds", 1000);
     211          65 :         date_trunc_single_time("second", 1000000);
     212          65 :         date_trunc_single_time("minute", 1000000 * 60);
     213          65 :         date_trunc_single_time("hour", LL_CONSTANT(1000000) * 60 * 60);
     214             : 
     215          65 :         if  ( strcasecmp(*scale, "day") == 0){
     216           4 :                 days = timestamp_date(*bt);
     217           4 :                 *dt = timestamp_fromdate(days);
     218             :         }
     219             : 
     220          65 :         if  ( strcasecmp(*scale, "week") == 0){
     221           6 :                 days = timestamp_date(*bt);
     222           6 :                 *dt = timestamp_fromdate(date_add_day(days, 1 - date_dayofweek(days)));
     223             :         }
     224             : 
     225          65 :         if  ( strcasecmp(*scale, "month") == 0){
     226           5 :                 days = timestamp_date(*bt);
     227           5 :                 *dt = timestamp_fromdate(date_create(date_year(days), date_month(days), 1));
     228             :         }
     229             : 
     230          65 :         if  ( strcasecmp(*scale, "quarter") == 0){
     231           4 :                 days = timestamp_date(*bt);
     232           4 :                 *dt = timestamp_fromdate(date_create(date_year(days), ((date_month(days) - 1) / 3) * 3 + 1, 1));
     233             :         }
     234             : 
     235          65 :         if  ( strcasecmp(*scale, "year") == 0){
     236           4 :                 days = timestamp_date(*bt);
     237           4 :                 *dt = timestamp_fromdate(date_create(date_year(days), 1, 1));
     238             :         }
     239             : 
     240          65 :         if  ( strcasecmp(*scale, "decade") == 0){
     241           7 :                 days = timestamp_date(*bt);
     242           7 :                 *dt = timestamp_fromdate(date_create((date_year(days) / 10) * 10, 1, 1));
     243             :         }
     244             : 
     245          65 :         if  ( strcasecmp(*scale, "century") == 0){
     246           9 :                 days = timestamp_date(*bt);
     247           9 :                 *dt = timestamp_fromdate(date_create((date_year(days) / 100) * 100, 1, 1));
     248             :         }
     249             : 
     250          65 :         if  ( strcasecmp(*scale, "millennium") == 0){
     251           6 :                 days = timestamp_date(*bt);
     252           6 :                 *dt = timestamp_fromdate(date_create((date_year(days) / 1000) * 1000, 1, 1));
     253             :         }
     254             :         return msg;
     255             : }

Generated by: LCOV version 1.14