| 1 | #include <dbd/common.h> |
| 2 | |
| 3 | const char *strlower(char *in) { |
| 4 | char *s = in; |
| 5 | |
| 6 | while(*s) { |
| 7 | *s= (*s <= 'Z' && *s >= 'A') ? (*s - 'A') + 'a' : *s; |
| 8 | s++; |
| 9 | } |
| 10 | |
| 11 | return in; |
| 12 | } |
| 13 | |
| 14 | /* |
| 15 | * replace '?' placeholders with {native_prefix}\d+ placeholders |
| 16 | * to be compatible with native API |
| 17 | */ |
| 18 | char *replace_placeholders(lua_State *L, char native_prefix, const char *sql) { |
| 19 | size_t len = strlen(sql); |
| 20 | int num_placeholders = 0; |
| 21 | int extra_space = 0; |
| 22 | int i; |
| 23 | char *newsql; |
| 24 | int newpos = 1; |
| 25 | int ph_num = 1; |
| 26 | int in_quote = 0; |
| 27 | char format_str[4]; |
| 28 | |
| 29 | format_str[0] = native_prefix; |
| 30 | format_str[1] = '%'; |
| 31 | format_str[2] = 'u'; |
| 32 | format_str[3] = '\0'; |
| 33 | |
| 34 | /* |
| 35 | * dumb count of all '?' |
| 36 | * this will match more placeholders than necessesary |
| 37 | * but it's safer to allocate more placeholders at the |
| 38 | * cost of a few bytes than risk a buffer overflow |
| 39 | */ |
| 40 | for (i = 1; i < len; i++) { |
| 41 | if (sql[i] == '?') { |
| 42 | num_placeholders++; |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | /* |
| 47 | * this is MAX_PLACEHOLDER_SIZE-1 because the '?' is |
| 48 | * replaced with '{native_prefix}' |
| 49 | */ |
| 50 | extra_space = num_placeholders * (MAX_PLACEHOLDER_SIZE-1); |
| 51 | |
| 52 | /* |
| 53 | * allocate a new string for the converted SQL statement |
| 54 | */ |
| 55 | newsql = malloc(sizeof(char) * (len+extra_space+1)); |
| 56 | memset(newsql, 0, sizeof(char) * (len+extra_space+1)); |
| 57 | |
| 58 | /* |
| 59 | * copy first char. In valid SQL this cannot be a placeholder |
| 60 | */ |
| 61 | newsql[0] = sql[0]; |
| 62 | |
| 63 | /* |
| 64 | * only replace '?' not in a single quoted string |
| 65 | */ |
| 66 | for (i = 1; i < len; i++) { |
| 67 | /* |
| 68 | * don't change the quote flag if the ''' is preceded |
| 69 | * by a '\' to account for escaping |
| 70 | */ |
| 71 | if (sql[i] == '\'' && sql[i-1] != '\\') { |
| 72 | in_quote = !in_quote; |
| 73 | } |
| 74 | |
| 75 | if (sql[i] == '?' && !in_quote) { |
| 76 | size_t n; |
| 77 | |
| 78 | if (ph_num > MAX_PLACEHOLDERS) { |
| 79 | luaL_error(L, "Sorry, you are using more than %d placeholders. Use %c{num} format instead", MAX_PLACEHOLDERS, native_prefix); |
| 80 | } |
| 81 | |
| 82 | n = snprintf(&newsql[newpos], MAX_PLACEHOLDER_SIZE, format_str, ph_num++); |
| 83 | |
| 84 | newpos += n; |
| 85 | } else { |
| 86 | newsql[newpos] = sql[i]; |
| 87 | newpos++; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /* |
| 92 | * terminate string on the last position |
| 93 | */ |
| 94 | newsql[newpos] = '\0'; |
| 95 | |
| 96 | /* fprintf(stderr, "[%s]\n", newsql); */ |
| 97 | return newsql; |
| 98 | } |