LCOV - code coverage report
Current view: top level - src - db_sql_wrap_string.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 73.5 % 49 36
Test Date: 2026-01-12 05:34:38 Functions: 100.0 % 1 1

            Line data    Source code
       1              : #include "precizer.h"
       2              : 
       3              : /**
       4              :  * @brief Wrap a plain string into an SQL literal with escaping.
       5              :  *
       6              :  * @param destination Pointer to a byte-sized memory descriptor receiving the wrapped string.
       7              :  * @param source      Zero-terminated string that should be quoted for SQL usage.
       8              :  *
       9              :  * @return Return code describing operation status.
      10              :  */
      11          154 : Return db_sql_wrap_string(
      12              :         memory     *destination,
      13              :         const char *source)
      14              : {
      15              :         /** Return status
      16              :          *  The status that will be passed to return() before exiting
      17              :          *  By default, the function worked without errors
      18              :          */
      19          154 :         Return status = SUCCESS;
      20              : 
      21          154 :         if(destination == NULL || source == NULL)
      22              :         {
      23            0 :                 slog(ERROR,"sql_wrap_string arguments must be non-NULL\n");
      24            0 :                 status = FAILURE;
      25              :         }
      26              : 
      27          154 :         if(SUCCESS == status && destination->element_size != sizeof(char))
      28              :         {
      29            0 :                 slog(ERROR,"sql_wrap_string requires byte-sized destination descriptor\n");
      30            0 :                 status = FAILURE;
      31              :         }
      32              : 
      33          154 :         size_t source_length = 0;
      34              : 
      35          154 :         if(SUCCESS == status)
      36              :         {
      37          154 :                 source_length = strlen(source);
      38              :         }
      39              : 
      40          154 :         size_t apostrophes = 0;
      41              : 
      42          154 :         if(SUCCESS == status)
      43              :         {
      44         4206 :                 for(size_t i = 0; i < source_length; ++i)
      45              :                 {
      46         4052 :                         if(source[i] == '\'')
      47              :                         {
      48           14 :                                 if(apostrophes == SIZE_MAX)
      49              :                                 {
      50            0 :                                         slog(ERROR,"sql_wrap_string apostrophe counter overflow\n");
      51            0 :                                         status = FAILURE;
      52            0 :                                         break;
      53              :                                 }
      54              : 
      55           14 :                                 ++apostrophes;
      56              :                         }
      57              :                 }
      58              :         }
      59              : 
      60          154 :         size_t required_elements = 0;
      61              : 
      62          154 :         if(SUCCESS == status)
      63              :         {
      64          154 :                 const size_t overhead = 3;
      65              : 
      66          154 :                 if(source_length > SIZE_MAX - apostrophes)
      67              :                 {
      68            0 :                         slog(ERROR,"sql_wrap_string overflow while adding escape budget\n");
      69            0 :                         status = FAILURE;
      70              :                 } else {
      71          154 :                         size_t base_length = source_length + apostrophes;
      72              : 
      73          154 :                         if(base_length > SIZE_MAX - overhead)
      74              :                         {
      75            0 :                                 slog(ERROR,"sql_wrap_string overflow before allocating terminator\n");
      76            0 :                                 status = FAILURE;
      77              :                         } else {
      78          154 :                                 required_elements = base_length + overhead;
      79              :                         }
      80              :                 }
      81              :         }
      82              : 
      83          154 :         run(resize(destination,required_elements));
      84              : 
      85          154 :         if(SUCCESS == status)
      86              :         {
      87          154 :                 unsigned char *destination_bytes = data(unsigned char,destination);
      88              : 
      89          154 :                 if(destination_bytes == NULL)
      90              :                 {
      91            0 :                         slog(ERROR,"sql_wrap_string destination pointer is NULL after resize\n");
      92            0 :                         status = FAILURE;
      93              :                 } else {
      94          154 :                         size_t write_index = 0;
      95              : 
      96          154 :                         destination_bytes[write_index++] = '\'';
      97              : 
      98         4206 :                         for(size_t i = 0; i < source_length; ++i)
      99              :                         {
     100         4052 :                                 unsigned char current_char = (unsigned char)source[i];
     101              : 
     102         4052 :                                 if(current_char == '\'')
     103              :                                 {
     104              :                                         /* Double apostrophes for SQL-compatible escaping */
     105           14 :                                         destination_bytes[write_index++] = '\'';
     106           14 :                                         destination_bytes[write_index++] = '\'';
     107              :                                 } else {
     108         4038 :                                         destination_bytes[write_index++] = current_char;
     109              :                                 }
     110              :                         }
     111              : 
     112          154 :                         destination_bytes[write_index++] = '\'';
     113          154 :                         destination_bytes[write_index] = '\0';
     114          154 :                         telemetry_string_padding_event();
     115              :                 }
     116              :         }
     117              : 
     118          154 :         provide(status);
     119              : }
        

Generated by: LCOV version 2.0-1