dbd/postgresql/statement.c

changeset 17
21c4feaeafe7
parent 12
014ba3ab3903
child 20
5ab0b30f8fbd
equal deleted inserted replaced
16:318e5dfd03b8 17:21c4feaeafe7
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

mercurial