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 : }
|