blob: 4913ced2d9d110eb5fcc1ef4e20d7b6b5d437d94 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 VMware Inc, Steven Rostedt
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include "trace-cmd.h"
#include "trace-local.h"
extern void breakpoint(void);
struct event_table {
struct tep_event *event;
struct tep_format_field **event_fields;
int *event_field_len;
size_t cnt;
FILE *fp;
};
static struct tep_format_field **event_common_fields;
static int nr_event_common_fields;
static struct event_table *event_table;
static int event_table_size;
int trace_sql_init(struct tracecmd_input *handle)
{
struct tep_handle *tep;
struct tep_event **event_list;
struct tep_event *event;
struct event_table *et;
unsigned int max_id = 0;
int i, f;
tep = tracecmd_get_pevent(handle);
if (!tep)
return -1;
event_list = tep_list_events(tep, TEP_EVENT_SORT_ID);
if (!event_list)
return -1;
for (i = 0; event_list[i]; i++) {
event = event_list[i];
if (event->id > max_id)
max_id = event->id;
}
event_table = calloc(max_id + 1, sizeof(*event_table));
event_table_size = max_id + 1;
for (i = 0; event_list[i]; i++) {
int e;
event = event_list[i];
if (event->id == 302)
breakpoint();
et = &event_table[event->id];
et->event = event;
if (!event_common_fields) {
event_common_fields = tep_event_common_fields(event);
if (!event_common_fields)
goto fail;
for (f = 0; event_common_fields[f]; f++)
;
nr_event_common_fields = f + 1;
}
et->event_fields = tep_event_fields(event);
if (!et->event_fields)
goto fail;
for (e = 0; et->event_fields[e]; e++)
;
et->event_field_len = calloc(e, sizeof(*et->event_field_len));
if (!et->event_field_len)
goto fail;
et->fp = tmpfile();
if (!et->fp)
goto fail;
}
return 0;
fail:
die("done!\n");
return -1;
}
static void write_string(FILE *fp, const char *str, int len)
{
if (!len)
len = strlen(str);
fputc('\'', fp);
fwrite(str, len, 1, fp);
fputc('\'', fp);
}
static void write_data(FILE *fp, struct tep_format_field *field,
struct tep_record *record, int *elen)
{
struct tep_handle *tep = field->event->tep;
unsigned int offset, len;
unsigned long long val;
char *data = record->data;
char buffer[64];
if (field->flags & TEP_FIELD_IS_ARRAY) {
offset = field->offset;
len = field->size;
if (field->flags & TEP_FIELD_IS_DYNAMIC) {
val = tep_read_number(tep, data + offset, len);
offset = val;
len = offset >> 16;
offset &= 0xffff;
}
if (field->flags & TEP_FIELD_IS_STRING) {
int l = strlen(data + offset);
if (l < len)
len = l;
write_string(fp, data + offset, len);
} else {
write_string(fp, "ARRAY", 0);
len = 5;
}
if (elen && (*elen) < len)
*elen = len;
return;
}
val = tep_read_number(tep, data + field->offset,
field->size);
sprintf(buffer, "%lld", val);
fwrite(buffer, strlen(buffer), 1, fp);
}
int trace_sql_record(struct tracecmd_input *handle, struct tep_record *record)
{
struct tep_handle *tep = tracecmd_get_pevent(handle);
struct tep_event *event = tep_find_event_by_record(tep, record);
struct event_table *et = &event_table[event->id];
char buffer[64];
int i;
if (event->id > event_table_size || !et->event)
return -1;
if (event->id == 302)
breakpoint();
if (et->cnt++)
fwrite(",(", 2, 1, et->fp);
else
fwrite("(", 1, 1, et->fp);
i = sprintf(buffer, "%lld", record->ts);
fwrite(buffer, i, 1, et->fp);
for (i = 0; event_common_fields[i]; i++) {
fwrite(",", 1, 1, et->fp);
write_data(et->fp, event_common_fields[i], record, NULL);
}
for (i = 0; et->event_fields[i]; i++) {
fwrite(",", 1, 1, et->fp);
write_data(et->fp, et->event_fields[i], record,
&et->event_field_len[i]);
}
fwrite(")", 1, 1, et->fp);
return 0;
}
static void write_header(struct tep_format_field *field, int flen)
{
printf("`%s` ", field->name);
if (field->flags & TEP_FIELD_IS_ARRAY) {
if (field->flags & TEP_FIELD_IS_STRING) {
if (field->flags & TEP_FIELD_IS_DYNAMIC) {
if (flen)
printf("VARCHAR(%d)", flen);
else
printf("VARCHAR(64)");
} else {
printf("CHAR(%d)", field->size);
}
} else {
printf("CHAR(5)");
}
} else {
printf("BIGINT");
}
printf(" NOT NULL");
}
static void print_sql_header(struct event_table *et)
{
const char *name = et->event->name;
int i;
printf("\n---\n--- Table structure for table `%s`\n---\n\n", name);
printf("DROP TABLE IF EXISTS `%s`;\n", name);
printf("CREATE TABLE `%s` (\n", name);
printf(" `common_timestamp` BIGINT NOT NULL");
for (i = 0; event_common_fields[i]; i++) {
printf(",\n ");
write_header(event_common_fields[i], 0);
}
for (i = 0; et->event_fields[i]; i++) {
printf(",\n ");
write_header(et->event_fields[i], et->event_field_len[i]);
}
printf("\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n");
printf("\n---\n--- Dumping data for table `%s`\n---\n\n", name);
printf("LOCK TABLES `%s` WRITE;\n", name);
printf("INSERT INTO `%s` VALUES ", name);
fflush(stdout);
fflush(et->fp);
}
int trace_sql_finish(struct tracecmd_input *handle)
{
struct event_table *et;
char buffer[BUFSIZ];
int i, r;
int fd;
for (i = 0; i < event_table_size; i++) {
et = &event_table[i];
if (!et->cnt)
continue;
print_sql_header(et);
fd = fileno(et->fp);
lseek(fd, 0, SEEK_SET);
do {
r = read(fd, buffer, BUFSIZ);
if (r > 0)
write(1, buffer, r);
} while (r > 0);
fclose(et->fp);
printf(";\n");
printf("UNLOCK TABLES;\n");
}
return 0;
}