51 |
57 |
52 int evsql_result_null (const struct evsql_result *res, size_t row, size_t col) { |
58 int evsql_result_null (const struct evsql_result *res, size_t row, size_t col) { |
53 switch (res->evsql->type) { |
59 switch (res->evsql->type) { |
54 case EVSQL_EVPQ: |
60 case EVSQL_EVPQ: |
55 return PQgetisnull(res->result.pq, row, col); |
61 return PQgetisnull(res->result.pq, row, col); |
|
62 |
|
63 default: |
|
64 FATAL("res->evsql->type"); |
|
65 } |
|
66 } |
|
67 |
|
68 int evsql_result_field (const struct evsql_result *res, size_t row, size_t col, char ** const ptr, size_t *size) { |
|
69 *ptr = NULL; |
|
70 |
|
71 switch (res->evsql->type) { |
|
72 case EVSQL_EVPQ: |
|
73 if (PQfformat(res->result.pq, col) != 1) |
|
74 ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col)); |
|
75 |
|
76 *size = PQgetlength(res->result.pq, row, col); |
|
77 *ptr = PQgetvalue(res->result.pq, row, col); |
|
78 |
|
79 return 0; |
56 |
80 |
57 default: |
81 default: |
58 FATAL("res->evsql->type"); |
82 FATAL("res->evsql->type"); |
59 } |
83 } |
60 |
84 |
61 error: |
85 error: |
62 return -1; |
86 return -1; |
63 } |
87 } |
64 |
88 |
65 int evsql_result_field (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size) { |
89 err_t evsql_result_check (struct evsql_result *res) { |
66 *ptr = NULL; |
90 // so simple... |
67 |
91 return res->error ? EIO : 0; |
68 switch (res->evsql->type) { |
|
69 case EVSQL_EVPQ: |
|
70 if (PQfformat(res->result.pq, col) != 1) |
|
71 ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col)); |
|
72 |
|
73 *size = PQgetlength(res->result.pq, row, col); |
|
74 *ptr = PQgetvalue(res->result.pq, row, col); |
|
75 |
|
76 return 0; |
|
77 |
|
78 default: |
|
79 FATAL("res->evsql->type"); |
|
80 } |
|
81 |
|
82 error: |
|
83 return -1; |
|
84 } |
92 } |
85 |
93 |
86 err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res) { |
94 err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res) { |
87 struct evsql_item_info *col; |
95 struct evsql_item_info *col; |
88 size_t cols = 0, nrows; |
96 size_t cols = 0, nrows; |
124 |
132 |
125 int evsql_result_next (struct evsql_result *res, ...) { |
133 int evsql_result_next (struct evsql_result *res, ...) { |
126 va_list vargs; |
134 va_list vargs; |
127 struct evsql_item_info *col; |
135 struct evsql_item_info *col; |
128 size_t col_idx, row_idx = res->row_offset; |
136 size_t col_idx, row_idx = res->row_offset; |
129 int err; |
137 err_t err; |
|
138 |
|
139 // ensure that evsql_result_begin has been called |
|
140 assert(res->info); |
130 |
141 |
131 // check if we're past the end |
142 // check if we're past the end |
132 if (row_idx >= evsql_result_rows(res)) |
143 if (row_idx >= evsql_result_rows(res)) |
133 return 0; |
144 return 0; |
134 |
145 |
135 // varargs |
146 // varargs |
136 va_start(vargs); |
147 va_start(vargs, res); |
137 |
148 |
138 for (col = info->columns, col_idx = 0; col->type; col++, col_idx++) { |
149 for (col = res->info->columns, col_idx = 0; col->type; col++, col_idx++) { |
139 char *value = NULL; |
150 char *value = NULL; |
140 size_t length = 0; |
151 size_t length = 0; |
141 |
152 |
142 // check for NULLs, then try and get the field value |
153 // check for NULLs, then try and get the field value |
143 if (evsql_result_null(res, row_idx, col_idx)) { |
154 if (evsql_result_null(res, row_idx, col_idx)) { |
144 if (!col->flags.null_ok) |
155 if (!col->flags.null_ok) |
145 XERROR(err = EINVAL, "r%zu:c%zu: NULL", row_idx, col_idx); |
156 XERROR(err = EINVAL, "r%zu:c%zu: NULL", row_idx, col_idx); |
146 |
157 |
147 } else if (evsql_result_field(row_idx, col_idx, &value, &length)) { |
158 } else if (evsql_result_field(res, row_idx, col_idx, &value, &length)) { |
148 EERROR(err = EINVAL); |
159 SERROR(err = EINVAL); |
149 |
160 |
150 } |
161 } |
151 |
162 |
152 // read the arg |
163 // read the arg |
153 switch (col->type) { |
164 switch (col->type) { |
161 } break; |
172 } break; |
162 |
173 |
163 case EVSQL_TYPE_STRING: { |
174 case EVSQL_TYPE_STRING: { |
164 char **str_ptr = va_arg(vargs, char **); |
175 char **str_ptr = va_arg(vargs, char **); |
165 |
176 |
166 if (value) |
177 if (value) { |
167 *str_ptr = value; |
178 *str_ptr = value; |
|
179 } |
168 |
180 |
169 } break; |
181 } break; |
170 |
182 |
171 case EVSQL_TYPE_UINT16: { |
183 case EVSQL_TYPE_UINT16: { |
172 uint16_t *uval_ptr = va_arg(vars, uint16_t *); |
184 uint16_t *uval_ptr = va_arg(vargs, uint16_t *); |
173 |
185 |
174 if (value) { |
186 if (!value) break; |
175 if (length != sizeof(uint16_t)) |
187 |
176 XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint16_t: %zu", row_idx, col_idx, length); |
188 if (length != sizeof(uint16_t)) XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint16_t: %zu", row_idx, col_idx, length); |
177 |
189 |
178 int16_t sval = ntohs(*((int16_t *) value)); |
190 int16_t sval = ntohs(*((int16_t *) value)); |
179 |
191 |
180 if (sval < 0) |
192 if (sval < 0) XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint16_t: %hd", row_idx, col_idx, (signed short) sval); |
181 XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint16_t: %d", row_idx, col_idx, sval); |
193 |
182 |
194 *uval_ptr = sval; |
183 *uval_ptr = sval; |
195 } break; |
184 } |
196 |
185 } break; |
197 case EVSQL_TYPE_UINT32: { |
|
198 uint32_t *uval_ptr = va_arg(vargs, uint32_t *); |
|
199 |
|
200 if (!value) break; |
|
201 |
|
202 if (length != sizeof(uint32_t)) XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint32_t: %zu", row_idx, col_idx, length); |
|
203 |
|
204 int32_t sval = ntohl(*((int32_t *) value)); |
|
205 |
|
206 if (sval < 0) XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint32_t: %ld", row_idx, col_idx, (signed long) sval); |
|
207 |
|
208 *uval_ptr = sval; |
|
209 } break; |
|
210 |
|
211 case EVSQL_TYPE_UINT64: { |
|
212 uint64_t *uval_ptr = va_arg(vargs, uint64_t *); |
|
213 |
|
214 if (!value) break; |
|
215 |
|
216 if (length != sizeof(uint64_t)) XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint64_t: %zu", row_idx, col_idx, length); |
|
217 |
|
218 int64_t sval = ntohq(*((int64_t *) value)); |
|
219 |
|
220 if (sval < 0) XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint64_t: %lld", row_idx, col_idx, (signed long long) sval); |
|
221 |
|
222 *uval_ptr = sval; |
|
223 } break; |
|
224 |
|
225 default: |
|
226 XERROR(err = EINVAL, "r%zu:c%zu: invalid type: %d", row_idx, col_idx, col->type); |
186 } |
227 } |
187 } |
228 } |
188 |
229 |
189 |
230 // row handled succesfully |
|
231 return 1; |
|
232 |
|
233 error: |
|
234 return -err; |
190 } |
235 } |
191 |
236 |
192 void evsql_result_end (struct evsql_result *res) { |
237 void evsql_result_end (struct evsql_result *res) { |
193 // not much more to it... |
238 // not much more to it... |
194 evsql_result_free(res); |
239 evsql_result_free(res); |
195 } |
240 } |
196 |
241 |
197 void evsql_result_free (struct evsql_result *res) { |
242 void evsql_result_free (struct evsql_result *res) { |
198 switch (res->evsql->type) { |
243 // note that the result itself might be NULL... |
199 case EVSQL_EVPQ: |
244 // in the case of internal-error results, these may be free'd multiple times! |
200 return PQclear(res->result.pq); |
245 switch (res->evsql->type) { |
201 |
246 case EVSQL_EVPQ: |
202 default: |
247 if (res->result.pq) |
203 FATAL("res->evsql->type"); |
248 return PQclear(res->result.pq); |
204 } |
249 |
205 } |
250 default: |
206 |
251 FATAL("res->evsql->type"); |
207 |
252 } |
|
253 } |
|
254 |
|
255 |