Branch data 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 : 233 : Return db_sql_wrap_string(
12 : : memory *destination,
13 : : const char *source)
14 : : {
15 : : /* Status returned by this function through provide()
16 : : Default value assumes successful completion */
17 : 233 : Return status = SUCCESS;
18 : :
19 [ + - - + ]: 233 : if(destination == NULL || source == NULL)
20 : : {
21 : 0 : slog(ERROR,"sql_wrap_string arguments must be non-NULL\n");
22 : 0 : status = FAILURE;
23 : : }
24 : :
25 [ + - - + ]: 233 : if(SUCCESS == status && destination->element_size != sizeof(char))
26 : : {
27 : 0 : slog(ERROR,"sql_wrap_string requires byte-sized destination descriptor\n");
28 : 0 : status = FAILURE;
29 : : }
30 : :
31 : 233 : size_t source_length = 0;
32 : :
33 [ + - ]: 233 : if(SUCCESS == status)
34 : : {
35 : 233 : source_length = strlen(source);
36 : : }
37 : :
38 : 233 : size_t apostrophes = 0;
39 : :
40 [ + - ]: 233 : if(SUCCESS == status)
41 : : {
42 [ + + ]: 6671 : for(size_t i = 0; i < source_length; ++i)
43 : : {
44 [ + + ]: 6438 : if(source[i] == '\'')
45 : : {
46 [ - + ]: 14 : if(apostrophes == SIZE_MAX)
47 : : {
48 : 0 : slog(ERROR,"sql_wrap_string apostrophe counter overflow\n");
49 : 0 : status = FAILURE;
50 : 0 : break;
51 : : }
52 : :
53 : 14 : ++apostrophes;
54 : : }
55 : : }
56 : : }
57 : :
58 : 233 : size_t required_elements = 0;
59 : :
60 [ + - ]: 233 : if(SUCCESS == status)
61 : : {
62 : 233 : const size_t overhead = 3;
63 : :
64 [ - + ]: 233 : if(source_length > SIZE_MAX - apostrophes)
65 : : {
66 : 0 : slog(ERROR,"sql_wrap_string overflow while adding escape budget\n");
67 : 0 : status = FAILURE;
68 : : } else {
69 : 233 : size_t base_length = source_length + apostrophes;
70 : :
71 [ - + ]: 233 : if(base_length > SIZE_MAX - overhead)
72 : : {
73 : 0 : slog(ERROR,"sql_wrap_string overflow before allocating terminator\n");
74 : 0 : status = FAILURE;
75 : : } else {
76 : 233 : required_elements = base_length + overhead;
77 : : }
78 : : }
79 : : }
80 : :
81 [ + - - + ]: 233 : run(resize(destination,required_elements));
82 : :
83 [ + - ]: 233 : if(SUCCESS == status)
84 : : {
85 : 233 : unsigned char *destination_bytes = data(unsigned char,destination);
86 : :
87 [ - + ]: 233 : if(destination_bytes == NULL)
88 : : {
89 : 0 : slog(ERROR,"sql_wrap_string destination pointer is NULL after resize\n");
90 : 0 : status = FAILURE;
91 : : } else {
92 : 233 : size_t write_index = 0;
93 : :
94 : 233 : destination_bytes[write_index++] = '\'';
95 : :
96 [ + + ]: 6671 : for(size_t i = 0; i < source_length; ++i)
97 : : {
98 : 6438 : unsigned char current_char = (unsigned char)source[i];
99 : :
100 [ + + ]: 6438 : if(current_char == '\'')
101 : : {
102 : : /* Double apostrophes for SQL-compatible escaping */
103 : 14 : destination_bytes[write_index++] = '\'';
104 : 14 : destination_bytes[write_index++] = '\'';
105 : : } else {
106 : 6424 : destination_bytes[write_index++] = current_char;
107 : : }
108 : : }
109 : :
110 : 233 : destination_bytes[write_index++] = '\'';
111 : 233 : destination_bytes[write_index] = '\0';
112 : 233 : telemetry_string_padding_event();
113 : : }
114 : : }
115 : :
116 : 233 : provide(status);
117 : : }
|