1 #include "pgreplay.h"
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <sys/time.h>
8
9 /* type for one replay line */
10 struct replay_item {
11 struct timeval time;
12 uint64_t session_id;
13 replay_type type;
14 uint16_t count;
15 char **data;
16 };
17
18 /* special replay_item that signals end-of-file */
19 static replay_item end_replay_item = {{0, 0}, 0, -1, 0, NULL};
20 replay_item * const end_item = &end_replay_item;
21
22 /* create common part of a replay_item */
replay_create(const struct timeval * time,uint64_t session_id,replay_type type,uint16_t count)23 static replay_item *replay_create(const struct timeval *time, uint64_t session_id, replay_type type, uint16_t count) {
24 replay_item *r;
25
26 r = malloc(sizeof(struct replay_item));
27 if (NULL == r) {
28 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)sizeof(struct replay_item));
29 return NULL;
30 }
31 r->time.tv_sec = time->tv_sec;
32 r->time.tv_usec = time->tv_usec;
33 r->session_id = session_id;
34 r->type = type;
35 r->count = count;
36 if (0 == count) {
37 r->data = NULL;
38 } else {
39 r->data = calloc(count, sizeof(char *));
40 if (NULL == r->data) {
41 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)count * sizeof(char *));
42 free(r);
43 return NULL;
44 }
45 }
46
47 return r;
48 }
49
replay_create_connect(const struct timeval * time,uint64_t session_id,const char * user,const char * database)50 replay_item *replay_create_connect(const struct timeval *time, uint64_t session_id, const char *user, const char *database) {
51 replay_item *r;
52
53 debug(3, "Entering replay_create_connect%s\n", "");
54
55 r = replay_create(time, session_id, pg_connect, 2);
56 if (NULL == r) {
57 return NULL;
58 }
59
60 (r->data)[0] = malloc(strlen(user) + 1);
61 if (NULL == (r->data)[0]) {
62 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)strlen(user) + 1);
63 free(r->data);
64 free(r);
65 return NULL;
66 }
67 strcpy((r->data)[0], user);
68
69 (r->data)[1] = malloc(strlen(database) + 1);
70 if (NULL == (r->data)[1]) {
71 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)strlen(user) + 1);
72 free((r->data)[0]);
73 free(r->data);
74 free(r);
75 return NULL;
76 }
77 strcpy((r->data)[1], database);
78
79 debug(3, "Leaving replay_create_connect%s\n", "");
80 return r;
81 }
82
replay_create_disconnect(const struct timeval * time,uint64_t session_id)83 replay_item *replay_create_disconnect(const struct timeval *time, uint64_t session_id) {
84 replay_item *r;
85
86 debug(3, "Entering replay_create_disconnect%s\n", "");
87
88 r = replay_create(time, session_id, pg_disconnect, 0);
89 if (NULL == r) {
90 return NULL;
91 }
92 debug(3, "Leaving replay_create_disconnect%s\n", "");
93 return r;
94 }
95
replay_create_execute(const struct timeval * time,uint64_t session_id,const char * statement)96 replay_item *replay_create_execute(const struct timeval *time, uint64_t session_id, const char *statement) {
97 replay_item *r;
98
99 debug(3, "Entering replay_create_execute%s\n", "");
100
101 r = replay_create(time, session_id, pg_execute, 1);
102 if (NULL == r) {
103 return NULL;
104 }
105
106 (r->data)[0] = malloc(strlen(statement) + 1);
107 if (NULL == (r->data)[0]) {
108 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)strlen(statement) + 1);
109 free(r->data);
110 free(r);
111 return NULL;
112 }
113 strcpy((r->data)[0], statement);
114
115 debug(3, "Leaving replay_create_execute%s\n", "");
116 return r;
117 }
118
replay_create_prepare(const struct timeval * time,uint64_t session_id,const char * name,const char * statement)119 replay_item *replay_create_prepare(const struct timeval *time, uint64_t session_id, const char *name, const char *statement) {
120 replay_item *r;
121
122 debug(3, "Entering replay_create_prepare%s\n", "");
123
124 r = replay_create(time, session_id, pg_prepare, 2);
125 if (NULL == r) {
126 return NULL;
127 }
128
129 (r->data)[0] = malloc(strlen(statement) + 1);
130 if (NULL == (r->data)[0]) {
131 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)strlen(statement) + 1);
132 free(r->data);
133 free(r);
134 return NULL;
135 }
136 strcpy((r->data)[0], statement);
137
138 (r->data)[1] = malloc(strlen(name) + 1);
139 if (NULL == (r->data)[1]) {
140 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)strlen(name) + 1);
141 free((r->data)[0]);
142 free(r->data);
143 free(r);
144 return NULL;
145 }
146 strcpy((r->data)[1], name);
147
148 debug(3, "Leaving replay_create_prepare%s\n", "");
149 return r;
150 }
151
replay_create_exec_prepared(const struct timeval * time,uint64_t session_id,const char * name,uint16_t count,char * const * values)152 replay_item *replay_create_exec_prepared(const struct timeval *time, uint64_t session_id, const char*name, uint16_t count, char * const *values) {
153 replay_item *r;
154 int i;
155
156 debug(3, "Entering replay_create_exec_prepared%s\n", "");
157
158 r = replay_create(time, session_id, pg_exec_prepared, count + 1);
159 if (NULL == r) {
160 return NULL;
161 }
162
163 (r->data)[0] = malloc(strlen(name) + 1);
164 if (NULL == (r->data)[0]) {
165 free(r->data);
166 free(r);
167 return NULL;
168 }
169 strcpy((r->data)[0], name);
170
171 for (i=1; i<count+1; ++i) {
172 if (values[i-1]) {
173 (r->data)[i] = malloc(strlen(values[i-1]) + 1);
174 if (NULL == (r->data)[i]) {
175 fprintf(stderr, "Cannot allocate %lu bytes of memory\n", (unsigned long)strlen(values[i-1]) + 1);
176 for (--i; i>=0; --i) {
177 if ((r->data)[i]) {
178 free((r->data)[i]);
179 }
180 }
181 free(r->data);
182 free(r);
183 return NULL;
184 }
185 strcpy((r->data)[i], values[i-1]);
186 } else {
187 (r->data)[i] = NULL;
188 }
189 }
190
191 debug(3, "Leaving replay_create_exec_prepared%s\n", "");
192 return r;
193 }
194
replay_create_cancel(const struct timeval * time,uint64_t session_id)195 replay_item *replay_create_cancel(const struct timeval *time, uint64_t session_id) {
196 replay_item *r;
197
198 debug(3, "Entering replay_create_cancel%s\n", "");
199
200 r = replay_create(time, session_id, pg_cancel, 0);
201 if (NULL == r) {
202 return NULL;
203 }
204 debug(3, "Leaving replay_create_cancel%s\n", "");
205 return r;
206 }
207
replay_free(replay_item * r)208 void replay_free(replay_item *r) {
209 int i;
210
211 debug(3, "Entering replay_free%s\n", "");
212
213 assert((pg_connect == r->type) || (pg_disconnect == r->type) || (pg_execute == r->type) || (pg_prepare == r->type) || (pg_exec_prepared == r->type) || (pg_cancel == r->type));
214
215 for (i=0; i<r->count; ++i) {
216 if ((r->data)[i]) {
217 free((r->data)[i]);
218 }
219 }
220 if (r->count) {
221 free(r->data);
222 }
223 free(r);
224
225 debug(3, "Leaving replay_free%s\n", "");
226 }
227
replay_get_type(const replay_item * r)228 replay_type replay_get_type(const replay_item *r) {
229 return r->type;
230 }
231
replay_get_session_id(const replay_item * r)232 uint64_t replay_get_session_id(const replay_item *r) {
233 return r->session_id;
234 }
235
replay_get_time(const replay_item * r)236 const struct timeval * replay_get_time(const replay_item *r) {
237 return &(r->time);
238 }
239
replay_get_statement(const replay_item * r)240 const char * replay_get_statement(const replay_item *r) {
241 assert((pg_execute == r->type) || (pg_prepare == r->type));
242
243 return (r->data)[0];
244 }
245
replay_get_name(const replay_item * r)246 const char * replay_get_name(const replay_item *r) {
247 assert((pg_prepare == r->type) || (pg_exec_prepared == r->type));
248
249 return (pg_prepare == r->type) ? (r->data)[1] : (r->data)[0];
250 }
251
replay_get_user(const replay_item * r)252 const char * replay_get_user(const replay_item *r) {
253 assert(pg_connect == r->type);
254
255 return (r->data)[0];
256 }
257
replay_get_database(const replay_item * r)258 const char * replay_get_database(const replay_item *r) {
259 assert(pg_connect == r->type);
260
261 return (r->data)[1];
262 }
263
replay_get_valuecount(const replay_item * r)264 int replay_get_valuecount(const replay_item *r) {
265 assert(pg_exec_prepared == r->type);
266
267 return r->count - 1;
268 }
269
replay_get_values(const replay_item * r)270 const char * const * replay_get_values(const replay_item *r) {
271 assert(pg_exec_prepared == r->type);
272
273 return (const char * const *)((r->data) + 1);
274 }
275
276 /* maximal part of a value for display */
277 #define SAMPLE_SIZE 100
278
replay_print_debug(const replay_item * r)279 void replay_print_debug(const replay_item *r) {
280 replay_type type;
281 int i;
282 char valuepart[SAMPLE_SIZE+4], *p;
283
284 valuepart[SAMPLE_SIZE] = '.';
285 valuepart[SAMPLE_SIZE+1] = '.';
286 valuepart[SAMPLE_SIZE+2] = '.';
287 valuepart[SAMPLE_SIZE+3] = '\0';
288
289 debug(1, "---------------------------%s\n", "");
290 debug(1, "Item: time = %lu.%06lu\n", (unsigned long)r->time.tv_sec, (unsigned long)r->time.tv_usec);
291 debug(1, " session id = 0x" UINT64_FORMAT "\n", r->session_id);
292 type = r->type;
293 debug(1, " type = %s\n",
294 (pg_connect == type) ? "connect" :
295 ((pg_disconnect == type) ? "disconnect" :
296 ((pg_execute == type) ? "execute" :
297 ((pg_prepare == type) ? "prepare" :
298 ((pg_exec_prepared == type) ? "exec_prepared" :
299 ((pg_cancel == type) ? "cancel" : "unknown")
300 )
301 )
302 )
303 )
304 );
305 switch (type) {
306 case pg_connect:
307 debug(1, " user = %s\n", replay_get_user(r));
308 debug(1, " database = %s\n", replay_get_database(r));
309 case pg_disconnect:
310 case pg_cancel:
311 break;
312 case pg_prepare:
313 debug(1, " name = %s\n", replay_get_name(r));
314 case pg_execute:
315 debug(1, " statement = %s\n", replay_get_statement(r));
316 break;
317 case pg_exec_prepared:
318 debug(1, " name = %s\n", replay_get_name(r));
319 for (i=0; i<replay_get_valuecount(r); ++i) {
320 /* print only the first SAMPLE_SIZE bytes of the argument */
321 if (replay_get_values(r)[i]) {
322 strncpy(valuepart, replay_get_values(r)[i], SAMPLE_SIZE);
323 p = valuepart;
324 } else {
325 p = NULL;
326 }
327 debug(1, " $%d = %s\n", i + 1, (NULL == p) ? "(null)" : p);
328 }
329 break;
330 }
331 debug(1, "---------------------------%s\n", "");
332 }
333