1 #include "dbd_postgresql.h" |
1 #include "dbd_postgresql.h" |
2 |
|
3 #define MAX_PLACEHOLDERS 9999 |
|
4 #define MAX_PLACEHOLDER_SIZE (1+4) /* $\d{4} */ |
|
5 |
2 |
6 static lua_push_type_t postgresql_to_lua_push(unsigned int postgresql_type) { |
3 static lua_push_type_t postgresql_to_lua_push(unsigned int postgresql_type) { |
7 lua_push_type_t lua_type; |
4 lua_push_type_t lua_type; |
8 |
5 |
9 switch(postgresql_type) { |
6 switch(postgresql_type) { |
26 } |
23 } |
27 |
24 |
28 return lua_type; |
25 return lua_type; |
29 } |
26 } |
30 |
27 |
31 /* |
|
32 * replace '?' placeholders with $\d+ placeholders |
|
33 * to be compatible with PSQL API |
|
34 */ |
|
35 static char *replace_placeholders(lua_State *L, const char *sql) { |
|
36 size_t len = strlen(sql); |
|
37 int num_placeholders = 0; |
|
38 int extra_space = 0; |
|
39 int i; |
|
40 char *newsql; |
|
41 int newpos = 1; |
|
42 int ph_num = 1; |
|
43 int in_quote = 0; |
|
44 |
|
45 /* |
|
46 * dumb count of all '?' |
|
47 * this will match more placeholders than necessesary |
|
48 * but it's safer to allocate more placeholders at the |
|
49 * cost of a few bytes than risk a buffer overflow |
|
50 */ |
|
51 for (i = 1; i < len; i++) { |
|
52 if (sql[i] == '?') { |
|
53 num_placeholders++; |
|
54 } |
|
55 } |
|
56 |
|
57 /* |
|
58 * this is MAX_PLACEHOLDER_SIZE-1 because the '?' is |
|
59 * replaced with '$' |
|
60 */ |
|
61 extra_space = num_placeholders * (MAX_PLACEHOLDER_SIZE-1); |
|
62 |
|
63 /* |
|
64 * allocate a new string for the converted SQL statement |
|
65 */ |
|
66 newsql = malloc(sizeof(char) * (len+extra_space+1)); |
|
67 memset(newsql, 0, sizeof(char) * (len+extra_space+1)); |
|
68 |
|
69 /* |
|
70 * copy first char. In valid SQL this cannot be a placeholder |
|
71 */ |
|
72 newsql[0] = sql[0]; |
|
73 |
|
74 /* |
|
75 * only replace '?' not in a single quoted string |
|
76 */ |
|
77 for (i = 1; i < len; i++) { |
|
78 /* |
|
79 * don't change the quote flag if the ''' is preceded |
|
80 * bt a '\' to account for escaping |
|
81 */ |
|
82 if (sql[i] == '\'' && sql[i-1] != '\\') { |
|
83 in_quote = !in_quote; |
|
84 } |
|
85 |
|
86 if (sql[i] == '?' && !in_quote) { |
|
87 size_t n; |
|
88 |
|
89 if (ph_num > MAX_PLACEHOLDERS) { |
|
90 luaL_error(L, "Sorry, you are using more than %d placeholders. Use ${num} format instead", MAX_PLACEHOLDERS); |
|
91 } |
|
92 |
|
93 n = snprintf(&newsql[newpos], MAX_PLACEHOLDER_SIZE, "$%u", ph_num++); |
|
94 |
|
95 newpos += n; |
|
96 } else { |
|
97 newsql[newpos] = sql[i]; |
|
98 newpos++; |
|
99 } |
|
100 } |
|
101 |
|
102 /* |
|
103 * terminate string on the last position |
|
104 */ |
|
105 newsql[newpos] = '\0'; |
|
106 |
|
107 /* fprintf(stderr, "[%s]\n", newsql); */ |
|
108 return newsql; |
|
109 } |
|
110 |
28 |
111 /* |
29 /* |
112 * success = statement:close() |
30 * success = statement:close() |
113 */ |
31 */ |
114 static int statement_close(lua_State *L) { |
32 static int statement_close(lua_State *L) { |
357 char name[IDLEN]; |
275 char name[IDLEN]; |
358 |
276 |
359 /* |
277 /* |
360 * convert SQL string into a PSQL API compatible SQL statement |
278 * convert SQL string into a PSQL API compatible SQL statement |
361 */ |
279 */ |
362 new_sql = replace_placeholders(L, sql_query); |
280 new_sql = replace_placeholders(L, '$', sql_query); |
363 |
281 |
364 snprintf(name, IDLEN, "%017u", ++conn->statement_id); |
282 snprintf(name, IDLEN, "%017u", ++conn->statement_id); |
365 |
283 |
366 result = PQprepare(conn->postgresql, name, new_sql, 0, NULL); |
284 result = PQprepare(conn->postgresql, name, new_sql, 0, NULL); |
367 |
285 |