| // 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; |
| } |