sql.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. // Copyright 2023 The go-fuzz-headers Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package gofuzzheaders
  15. import (
  16. "fmt"
  17. "strings"
  18. )
  19. // returns a keyword by index
  20. func getKeyword(f *ConsumeFuzzer) (string, error) {
  21. index, err := f.GetInt()
  22. if err != nil {
  23. return keywords[0], err
  24. }
  25. for i, k := range keywords {
  26. if i == index {
  27. return k, nil
  28. }
  29. }
  30. return keywords[0], fmt.Errorf("could not get a kw")
  31. }
  32. // Simple utility function to check if a string
  33. // slice contains a string.
  34. func containsString(s []string, e string) bool {
  35. for _, a := range s {
  36. if a == e {
  37. return true
  38. }
  39. }
  40. return false
  41. }
  42. // These keywords are used specifically for fuzzing Vitess
  43. var keywords = []string{
  44. "accessible", "action", "add", "after", "against", "algorithm",
  45. "all", "alter", "always", "analyze", "and", "as", "asc", "asensitive",
  46. "auto_increment", "avg_row_length", "before", "begin", "between",
  47. "bigint", "binary", "_binary", "_utf8mb4", "_utf8", "_latin1", "bit",
  48. "blob", "bool", "boolean", "both", "by", "call", "cancel", "cascade",
  49. "cascaded", "case", "cast", "channel", "change", "char", "character",
  50. "charset", "check", "checksum", "coalesce", "code", "collate", "collation",
  51. "column", "columns", "comment", "committed", "commit", "compact", "complete",
  52. "compressed", "compression", "condition", "connection", "constraint", "continue",
  53. "convert", "copy", "cume_dist", "substr", "substring", "create", "cross",
  54. "csv", "current_date", "current_time", "current_timestamp", "current_user",
  55. "cursor", "data", "database", "databases", "day", "day_hour", "day_microsecond",
  56. "day_minute", "day_second", "date", "datetime", "dec", "decimal", "declare",
  57. "default", "definer", "delay_key_write", "delayed", "delete", "dense_rank",
  58. "desc", "describe", "deterministic", "directory", "disable", "discard",
  59. "disk", "distinct", "distinctrow", "div", "double", "do", "drop", "dumpfile",
  60. "duplicate", "dynamic", "each", "else", "elseif", "empty", "enable",
  61. "enclosed", "encryption", "end", "enforced", "engine", "engines", "enum",
  62. "error", "escape", "escaped", "event", "exchange", "exclusive", "exists",
  63. "exit", "explain", "expansion", "export", "extended", "extract", "false",
  64. "fetch", "fields", "first", "first_value", "fixed", "float", "float4",
  65. "float8", "flush", "for", "force", "foreign", "format", "from", "full",
  66. "fulltext", "function", "general", "generated", "geometry", "geometrycollection",
  67. "get", "global", "gtid_executed", "grant", "group", "grouping", "groups",
  68. "group_concat", "having", "header", "high_priority", "hosts", "hour", "hour_microsecond",
  69. "hour_minute", "hour_second", "if", "ignore", "import", "in", "index", "indexes",
  70. "infile", "inout", "inner", "inplace", "insensitive", "insert", "insert_method",
  71. "int", "int1", "int2", "int3", "int4", "int8", "integer", "interval",
  72. "into", "io_after_gtids", "is", "isolation", "iterate", "invoker", "join",
  73. "json", "json_table", "key", "keys", "keyspaces", "key_block_size", "kill", "lag",
  74. "language", "last", "last_value", "last_insert_id", "lateral", "lead", "leading",
  75. "leave", "left", "less", "level", "like", "limit", "linear", "lines",
  76. "linestring", "load", "local", "localtime", "localtimestamp", "lock", "logs",
  77. "long", "longblob", "longtext", "loop", "low_priority", "manifest",
  78. "master_bind", "match", "max_rows", "maxvalue", "mediumblob", "mediumint",
  79. "mediumtext", "memory", "merge", "microsecond", "middleint", "min_rows", "minute",
  80. "minute_microsecond", "minute_second", "mod", "mode", "modify", "modifies",
  81. "multilinestring", "multipoint", "multipolygon", "month", "name",
  82. "names", "natural", "nchar", "next", "no", "none", "not", "no_write_to_binlog",
  83. "nth_value", "ntile", "null", "numeric", "of", "off", "offset", "on",
  84. "only", "open", "optimize", "optimizer_costs", "option", "optionally",
  85. "or", "order", "out", "outer", "outfile", "over", "overwrite", "pack_keys",
  86. "parser", "partition", "partitioning", "password", "percent_rank", "plugins",
  87. "point", "polygon", "precision", "primary", "privileges", "processlist",
  88. "procedure", "query", "quarter", "range", "rank", "read", "reads", "read_write",
  89. "real", "rebuild", "recursive", "redundant", "references", "regexp", "relay",
  90. "release", "remove", "rename", "reorganize", "repair", "repeat", "repeatable",
  91. "replace", "require", "resignal", "restrict", "return", "retry", "revert",
  92. "revoke", "right", "rlike", "rollback", "row", "row_format", "row_number",
  93. "rows", "s3", "savepoint", "schema", "schemas", "second", "second_microsecond",
  94. "security", "select", "sensitive", "separator", "sequence", "serializable",
  95. "session", "set", "share", "shared", "show", "signal", "signed", "slow",
  96. "smallint", "spatial", "specific", "sql", "sqlexception", "sqlstate",
  97. "sqlwarning", "sql_big_result", "sql_cache", "sql_calc_found_rows",
  98. "sql_no_cache", "sql_small_result", "ssl", "start", "starting",
  99. "stats_auto_recalc", "stats_persistent", "stats_sample_pages", "status",
  100. "storage", "stored", "straight_join", "stream", "system", "vstream",
  101. "table", "tables", "tablespace", "temporary", "temptable", "terminated",
  102. "text", "than", "then", "time", "timestamp", "timestampadd", "timestampdiff",
  103. "tinyblob", "tinyint", "tinytext", "to", "trailing", "transaction", "tree",
  104. "traditional", "trigger", "triggers", "true", "truncate", "uncommitted",
  105. "undefined", "undo", "union", "unique", "unlock", "unsigned", "update",
  106. "upgrade", "usage", "use", "user", "user_resources", "using", "utc_date",
  107. "utc_time", "utc_timestamp", "validation", "values", "variables", "varbinary",
  108. "varchar", "varcharacter", "varying", "vgtid_executed", "virtual", "vindex",
  109. "vindexes", "view", "vitess", "vitess_keyspaces", "vitess_metadata",
  110. "vitess_migration", "vitess_migrations", "vitess_replication_status",
  111. "vitess_shards", "vitess_tablets", "vschema", "warnings", "when",
  112. "where", "while", "window", "with", "without", "work", "write", "xor",
  113. "year", "year_month", "zerofill",
  114. }
  115. // Keywords that could get an additional keyword
  116. var needCustomString = []string{
  117. "DISTINCTROW", "FROM", // Select keywords:
  118. "GROUP BY", "HAVING", "WINDOW",
  119. "FOR",
  120. "ORDER BY", "LIMIT",
  121. "INTO", "PARTITION", "AS", // Insert Keywords:
  122. "ON DUPLICATE KEY UPDATE",
  123. "WHERE", "LIMIT", // Delete keywords
  124. "INFILE", "INTO TABLE", "CHARACTER SET", // Load keywords
  125. "TERMINATED BY", "ENCLOSED BY",
  126. "ESCAPED BY", "STARTING BY",
  127. "TERMINATED BY", "STARTING BY",
  128. "IGNORE",
  129. "VALUE", "VALUES", // Replace tokens
  130. "SET", // Update tokens
  131. "ENGINE =", // Drop tokens
  132. "DEFINER =", "ON SCHEDULE", "RENAME TO", // Alter tokens
  133. "COMMENT", "DO", "INITIAL_SIZE = ", "OPTIONS",
  134. }
  135. var alterTableTokens = [][]string{
  136. {"CUSTOM_FUZZ_STRING"},
  137. {"CUSTOM_ALTTER_TABLE_OPTIONS"},
  138. {"PARTITION_OPTIONS_FOR_ALTER_TABLE"},
  139. }
  140. var alterTokens = [][]string{
  141. {
  142. "DATABASE", "SCHEMA", "DEFINER = ", "EVENT", "FUNCTION", "INSTANCE",
  143. "LOGFILE GROUP", "PROCEDURE", "SERVER",
  144. },
  145. {"CUSTOM_FUZZ_STRING"},
  146. {
  147. "ON SCHEDULE", "ON COMPLETION PRESERVE", "ON COMPLETION NOT PRESERVE",
  148. "ADD UNDOFILE", "OPTIONS",
  149. },
  150. {"RENAME TO", "INITIAL_SIZE = "},
  151. {"ENABLE", "DISABLE", "DISABLE ON SLAVE", "ENGINE"},
  152. {"COMMENT"},
  153. {"DO"},
  154. }
  155. var setTokens = [][]string{
  156. {"CHARACTER SET", "CHARSET", "CUSTOM_FUZZ_STRING", "NAMES"},
  157. {"CUSTOM_FUZZ_STRING", "DEFAULT", "="},
  158. {"CUSTOM_FUZZ_STRING"},
  159. }
  160. var dropTokens = [][]string{
  161. {"TEMPORARY", "UNDO"},
  162. {
  163. "DATABASE", "SCHEMA", "EVENT", "INDEX", "LOGFILE GROUP",
  164. "PROCEDURE", "FUNCTION", "SERVER", "SPATIAL REFERENCE SYSTEM",
  165. "TABLE", "TABLESPACE", "TRIGGER", "VIEW",
  166. },
  167. {"IF EXISTS"},
  168. {"CUSTOM_FUZZ_STRING"},
  169. {"ON", "ENGINE = ", "RESTRICT", "CASCADE"},
  170. }
  171. var renameTokens = [][]string{
  172. {"TABLE"},
  173. {"CUSTOM_FUZZ_STRING"},
  174. {"TO"},
  175. {"CUSTOM_FUZZ_STRING"},
  176. }
  177. var truncateTokens = [][]string{
  178. {"TABLE"},
  179. {"CUSTOM_FUZZ_STRING"},
  180. }
  181. var createTokens = [][]string{
  182. {"OR REPLACE", "TEMPORARY", "UNDO"}, // For create spatial reference system
  183. {
  184. "UNIQUE", "FULLTEXT", "SPATIAL", "ALGORITHM = UNDEFINED", "ALGORITHM = MERGE",
  185. "ALGORITHM = TEMPTABLE",
  186. },
  187. {
  188. "DATABASE", "SCHEMA", "EVENT", "FUNCTION", "INDEX", "LOGFILE GROUP",
  189. "PROCEDURE", "SERVER", "SPATIAL REFERENCE SYSTEM", "TABLE", "TABLESPACE",
  190. "TRIGGER", "VIEW",
  191. },
  192. {"IF NOT EXISTS"},
  193. {"CUSTOM_FUZZ_STRING"},
  194. }
  195. /*
  196. // For future use.
  197. var updateTokens = [][]string{
  198. {"LOW_PRIORITY"},
  199. {"IGNORE"},
  200. {"SET"},
  201. {"WHERE"},
  202. {"ORDER BY"},
  203. {"LIMIT"},
  204. }
  205. */
  206. var replaceTokens = [][]string{
  207. {"LOW_PRIORITY", "DELAYED"},
  208. {"INTO"},
  209. {"PARTITION"},
  210. {"CUSTOM_FUZZ_STRING"},
  211. {"VALUES", "VALUE"},
  212. }
  213. var loadTokens = [][]string{
  214. {"DATA"},
  215. {"LOW_PRIORITY", "CONCURRENT", "LOCAL"},
  216. {"INFILE"},
  217. {"REPLACE", "IGNORE"},
  218. {"INTO TABLE"},
  219. {"PARTITION"},
  220. {"CHARACTER SET"},
  221. {"FIELDS", "COLUMNS"},
  222. {"TERMINATED BY"},
  223. {"OPTIONALLY"},
  224. {"ENCLOSED BY"},
  225. {"ESCAPED BY"},
  226. {"LINES"},
  227. {"STARTING BY"},
  228. {"TERMINATED BY"},
  229. {"IGNORE"},
  230. {"LINES", "ROWS"},
  231. {"CUSTOM_FUZZ_STRING"},
  232. }
  233. // These Are everything that comes after "INSERT"
  234. var insertTokens = [][]string{
  235. {"LOW_PRIORITY", "DELAYED", "HIGH_PRIORITY", "IGNORE"},
  236. {"INTO"},
  237. {"PARTITION"},
  238. {"CUSTOM_FUZZ_STRING"},
  239. {"AS"},
  240. {"ON DUPLICATE KEY UPDATE"},
  241. }
  242. // These are everything that comes after "SELECT"
  243. var selectTokens = [][]string{
  244. {"*", "CUSTOM_FUZZ_STRING", "DISTINCTROW"},
  245. {"HIGH_PRIORITY"},
  246. {"STRAIGHT_JOIN"},
  247. {"SQL_SMALL_RESULT", "SQL_BIG_RESULT", "SQL_BUFFER_RESULT"},
  248. {"SQL_NO_CACHE", "SQL_CALC_FOUND_ROWS"},
  249. {"CUSTOM_FUZZ_STRING"},
  250. {"FROM"},
  251. {"WHERE"},
  252. {"GROUP BY"},
  253. {"HAVING"},
  254. {"WINDOW"},
  255. {"ORDER BY"},
  256. {"LIMIT"},
  257. {"CUSTOM_FUZZ_STRING"},
  258. {"FOR"},
  259. }
  260. // These are everything that comes after "DELETE"
  261. var deleteTokens = [][]string{
  262. {"LOW_PRIORITY", "QUICK", "IGNORE", "FROM", "AS"},
  263. {"PARTITION"},
  264. {"WHERE"},
  265. {"ORDER BY"},
  266. {"LIMIT"},
  267. }
  268. var alter_table_options = []string{
  269. "ADD", "COLUMN", "FIRST", "AFTER", "INDEX", "KEY", "FULLTEXT", "SPATIAL",
  270. "CONSTRAINT", "UNIQUE", "FOREIGN KEY", "CHECK", "ENFORCED", "DROP", "ALTER",
  271. "NOT", "INPLACE", "COPY", "SET", "VISIBLE", "INVISIBLE", "DEFAULT", "CHANGE",
  272. "CHARACTER SET", "COLLATE", "DISABLE", "ENABLE", "KEYS", "TABLESPACE", "LOCK",
  273. "FORCE", "MODIFY", "SHARED", "EXCLUSIVE", "NONE", "ORDER BY", "RENAME COLUMN",
  274. "AS", "=", "ASC", "DESC", "WITH", "WITHOUT", "VALIDATION", "ADD PARTITION",
  275. "DROP PARTITION", "DISCARD PARTITION", "IMPORT PARTITION", "TRUNCATE PARTITION",
  276. "COALESCE PARTITION", "REORGANIZE PARTITION", "EXCHANGE PARTITION",
  277. "ANALYZE PARTITION", "CHECK PARTITION", "OPTIMIZE PARTITION", "REBUILD PARTITION",
  278. "REPAIR PARTITION", "REMOVE PARTITIONING", "USING", "BTREE", "HASH", "COMMENT",
  279. "KEY_BLOCK_SIZE", "WITH PARSER", "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG_ROW_LENGTH",
  280. "CHECKSUM", "INSERT_METHOD", "ROW_FORMAT", "DYNAMIC", "FIXED", "COMPRESSED", "REDUNDANT",
  281. "COMPACT", "SECONDARY_ENGINE_ATTRIBUTE", "STATS_AUTO_RECALC", "STATS_PERSISTENT",
  282. "STATS_SAMPLE_PAGES", "ZLIB", "LZ4", "ENGINE_ATTRIBUTE", "KEY_BLOCK_SIZE", "MAX_ROWS",
  283. "MIN_ROWS", "PACK_KEYS", "PASSWORD", "COMPRESSION", "CONNECTION", "DIRECTORY",
  284. "DELAY_KEY_WRITE", "ENCRYPTION", "STORAGE", "DISK", "MEMORY", "UNION",
  285. }
  286. // Creates an 'alter table' statement. 'alter table' is an exception
  287. // in that it has its own function. The majority of statements
  288. // are created by 'createStmt()'.
  289. func createAlterTableStmt(f *ConsumeFuzzer) (string, error) {
  290. maxArgs, err := f.GetInt()
  291. if err != nil {
  292. return "", err
  293. }
  294. maxArgs = maxArgs % 30
  295. if maxArgs == 0 {
  296. return "", fmt.Errorf("could not create alter table stmt")
  297. }
  298. var stmt strings.Builder
  299. stmt.WriteString("ALTER TABLE ")
  300. for i := 0; i < maxArgs; i++ {
  301. // Calculate if we get existing token or custom string
  302. tokenType, err := f.GetInt()
  303. if err != nil {
  304. return "", err
  305. }
  306. if tokenType%4 == 1 {
  307. customString, err := f.GetString()
  308. if err != nil {
  309. return "", err
  310. }
  311. stmt.WriteString(" " + customString)
  312. } else {
  313. tokenIndex, err := f.GetInt()
  314. if err != nil {
  315. return "", err
  316. }
  317. stmt.WriteString(" " + alter_table_options[tokenIndex%len(alter_table_options)])
  318. }
  319. }
  320. return stmt.String(), nil
  321. }
  322. func chooseToken(tokens []string, f *ConsumeFuzzer) (string, error) {
  323. index, err := f.GetInt()
  324. if err != nil {
  325. return "", err
  326. }
  327. var token strings.Builder
  328. token.WriteString(tokens[index%len(tokens)])
  329. if token.String() == "CUSTOM_FUZZ_STRING" {
  330. customFuzzString, err := f.GetString()
  331. if err != nil {
  332. return "", err
  333. }
  334. return customFuzzString, nil
  335. }
  336. // Check if token requires an argument
  337. if containsString(needCustomString, token.String()) {
  338. customFuzzString, err := f.GetString()
  339. if err != nil {
  340. return "", err
  341. }
  342. token.WriteString(" " + customFuzzString)
  343. }
  344. return token.String(), nil
  345. }
  346. var stmtTypes = map[string][][]string{
  347. "DELETE": deleteTokens,
  348. "INSERT": insertTokens,
  349. "SELECT": selectTokens,
  350. "LOAD": loadTokens,
  351. "REPLACE": replaceTokens,
  352. "CREATE": createTokens,
  353. "DROP": dropTokens,
  354. "RENAME": renameTokens,
  355. "TRUNCATE": truncateTokens,
  356. "SET": setTokens,
  357. "ALTER": alterTokens,
  358. "ALTER TABLE": alterTableTokens, // ALTER TABLE has its own set of tokens
  359. }
  360. var stmtTypeEnum = map[int]string{
  361. 0: "DELETE",
  362. 1: "INSERT",
  363. 2: "SELECT",
  364. 3: "LOAD",
  365. 4: "REPLACE",
  366. 5: "CREATE",
  367. 6: "DROP",
  368. 7: "RENAME",
  369. 8: "TRUNCATE",
  370. 9: "SET",
  371. 10: "ALTER",
  372. 11: "ALTER TABLE",
  373. }
  374. func createStmt(f *ConsumeFuzzer) (string, error) {
  375. stmtIndex, err := f.GetInt()
  376. if err != nil {
  377. return "", err
  378. }
  379. stmtIndex = stmtIndex % len(stmtTypes)
  380. queryType := stmtTypeEnum[stmtIndex]
  381. tokens := stmtTypes[queryType]
  382. // We have custom creator for ALTER TABLE
  383. if queryType == "ALTER TABLE" {
  384. query, err := createAlterTableStmt(f)
  385. if err != nil {
  386. return "", err
  387. }
  388. return query, nil
  389. }
  390. // Here we are creating a query that is not
  391. // an 'alter table' query. For available
  392. // queries, see "stmtTypes"
  393. // First specify the first query keyword:
  394. var query strings.Builder
  395. query.WriteString(queryType)
  396. // Next create the args for the
  397. queryArgs, err := createStmtArgs(tokens, f)
  398. if err != nil {
  399. return "", err
  400. }
  401. query.WriteString(" " + queryArgs)
  402. return query.String(), nil
  403. }
  404. // Creates the arguments of a statements. In a select statement
  405. // that would be everything after "select".
  406. func createStmtArgs(tokenslice [][]string, f *ConsumeFuzzer) (string, error) {
  407. var query, token strings.Builder
  408. // We go through the tokens in the tokenslice,
  409. // create the respective token and add it to
  410. // "query"
  411. for _, tokens := range tokenslice {
  412. // For extra randomization, the fuzzer can
  413. // choose to not include this token.
  414. includeThisToken, err := f.GetBool()
  415. if err != nil {
  416. return "", err
  417. }
  418. if !includeThisToken {
  419. continue
  420. }
  421. // There may be several tokens to choose from:
  422. if len(tokens) > 1 {
  423. chosenToken, err := chooseToken(tokens, f)
  424. if err != nil {
  425. return "", err
  426. }
  427. query.WriteString(" " + chosenToken)
  428. } else {
  429. token.WriteString(tokens[0])
  430. // In case the token is "CUSTOM_FUZZ_STRING"
  431. // we will then create a non-structured string
  432. if token.String() == "CUSTOM_FUZZ_STRING" {
  433. customFuzzString, err := f.GetString()
  434. if err != nil {
  435. return "", err
  436. }
  437. query.WriteString(" " + customFuzzString)
  438. continue
  439. }
  440. // Check if token requires an argument.
  441. // Tokens that take an argument can be found
  442. // in 'needCustomString'. If so, we add a
  443. // non-structured string to the token.
  444. if containsString(needCustomString, token.String()) {
  445. customFuzzString, err := f.GetString()
  446. if err != nil {
  447. return "", err
  448. }
  449. token.WriteString(fmt.Sprintf(" %s", customFuzzString))
  450. }
  451. query.WriteString(fmt.Sprintf(" %s", token.String()))
  452. }
  453. }
  454. return query.String(), nil
  455. }
  456. // Creates a semi-structured query. It creates a string
  457. // that is a combination of the keywords and random strings.
  458. func createQuery(f *ConsumeFuzzer) (string, error) {
  459. queryLen, err := f.GetInt()
  460. if err != nil {
  461. return "", err
  462. }
  463. maxLen := queryLen % 60
  464. if maxLen == 0 {
  465. return "", fmt.Errorf("could not create a query")
  466. }
  467. var query strings.Builder
  468. for i := 0; i < maxLen; i++ {
  469. // Get a new token:
  470. useKeyword, err := f.GetBool()
  471. if err != nil {
  472. return "", err
  473. }
  474. if useKeyword {
  475. keyword, err := getKeyword(f)
  476. if err != nil {
  477. return "", err
  478. }
  479. query.WriteString(" " + keyword)
  480. } else {
  481. customString, err := f.GetString()
  482. if err != nil {
  483. return "", err
  484. }
  485. query.WriteString(" " + customString)
  486. }
  487. }
  488. if query.String() == "" {
  489. return "", fmt.Errorf("could not create a query")
  490. }
  491. return query.String(), nil
  492. }
  493. // GetSQLString is the API that users interact with.
  494. //
  495. // Usage:
  496. //
  497. // f := NewConsumer(data)
  498. // sqlString, err := f.GetSQLString()
  499. func (f *ConsumeFuzzer) GetSQLString() (string, error) {
  500. var query string
  501. veryStructured, err := f.GetBool()
  502. if err != nil {
  503. return "", err
  504. }
  505. if veryStructured {
  506. query, err = createStmt(f)
  507. if err != nil {
  508. return "", err
  509. }
  510. } else {
  511. query, err = createQuery(f)
  512. if err != nil {
  513. return "", err
  514. }
  515. }
  516. return query, nil
  517. }