22#include <stdio.h>
33#include <string.h>
44
5- #define MAX_QUERY_SIZE 65536 /* queries larger than this are rejected */
5+ #define MAX_QUERY_SIZE 65536 /* queries larger than this are rejected */
66
77#include "libpg_query/pg_query.h"
88
@@ -25,17 +25,37 @@ ERL_NIF_TERM make_binary(ErlNifEnv *env, char *source) {
2525 return binary ;
2626}
2727
28- static ERL_NIF_TERM max_query_size (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
28+ ERL_NIF_TERM query_too_long_error (ErlNifEnv * env , size_t query_size ) {
29+ char error_msg [128 ];
30+ snprintf (error_msg , 128 ,
31+ "cannot parse query: query size %lu is bigger than maximum size %i" ,
32+ query_size , MAX_QUERY_SIZE );
33+ ERL_NIF_TERM error_map = make_error_response (env , error_msg );
34+ return enif_make_tuple2 (env , enif_make_atom (env , "error" ), error_map );
35+ }
36+
37+ ERL_NIF_TERM make_error_response (ErlNifEnv * env , char * message ) {
38+ ERL_NIF_TERM error_map = enif_make_new_map (env );
39+ if (!enif_make_map_put (env , error_map , enif_make_atom (env , "message" ),
40+ make_binary (env , message ), & error_map )) {
41+ return enif_raise_exception (env , make_binary (env , "failed to update map" ));
42+ }
43+ return error_map ;
44+ }
45+
46+ static ERL_NIF_TERM max_query_size (ErlNifEnv * env , int argc ,
47+ const ERL_NIF_TERM argv []) {
2948 return enif_make_int64 (env , MAX_QUERY_SIZE );
3049}
3150
32- static ERL_NIF_TERM parse_query (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
51+ static ERL_NIF_TERM parse_query (ErlNifEnv * env , int argc ,
52+ const ERL_NIF_TERM argv []) {
3353 ErlNifBinary query ;
3454 ERL_NIF_TERM term ;
3555
3656 if (argc == 1 && enif_inspect_binary (env , argv [0 ], & query )) {
3757 if (query .size >= MAX_QUERY_SIZE ) {
38- return enif_make_badarg (env );
58+ return query_too_long_error (env , query . size );
3959 }
4060
4161 // add one more byte for the null termination
@@ -49,27 +69,14 @@ static ERL_NIF_TERM parse_query(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg
4969 PgQueryProtobufParseResult result = pg_query_parse_protobuf (statement );
5070
5171 if (result .error ) {
52- ERL_NIF_TERM error_map = enif_make_new_map (env );
53-
54- if (!enif_make_map_put (
55- env ,
56- error_map ,
57- enif_make_atom (env , "message" ),
58- make_binary (env , result .error -> message ),
59- & error_map
60- )) {
61- return enif_raise_exception (env , make_binary (env , "failed to update map" ));
62- }
63-
64- if (!enif_make_map_put (
65- env ,
66- error_map ,
67- enif_make_atom (env , "cursorpos" ),
68- // drop the cursorpos by one, so it's zero-indexed
69- enif_make_int (env , result .error -> cursorpos - 1 ),
70- & error_map
71- )) {
72- return enif_raise_exception (env , make_binary (env , "failed to update map" ));
72+ ERL_NIF_TERM error_map = make_error_response (env , result .error -> message );
73+
74+ if (!enif_make_map_put (env , error_map , enif_make_atom (env , "cursorpos" ),
75+ // drop the cursorpos by one, so it's zero-indexed
76+ enif_make_int (env , result .error -> cursorpos - 1 ),
77+ & error_map )) {
78+ return enif_raise_exception (env ,
79+ make_binary (env , "failed to update map" ));
7380 }
7481
7582 term = enif_make_tuple2 (env , enif_make_atom (env , "error" ), error_map );
@@ -86,7 +93,7 @@ static ERL_NIF_TERM parse_query(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg
8693}
8794
8895static ERL_NIF_TERM deparse_query (ErlNifEnv * env , int argc ,
89- const ERL_NIF_TERM argv []) {
96+ const ERL_NIF_TERM argv []) {
9097 ErlNifBinary proto ;
9198 ERL_NIF_TERM term ;
9299
@@ -100,14 +107,11 @@ static ERL_NIF_TERM deparse_query(ErlNifEnv *env, int argc,
100107 if (result .error ) {
101108 ERL_NIF_TERM error_map = enif_make_new_map (env );
102109
103- if (!enif_make_map_put (
104- env ,
105- error_map ,
106- enif_make_atom (env , "message" ),
107- make_binary (env , result .error -> message ),
108- & error_map
109- )) {
110- return enif_raise_exception (env , make_binary (env , "failed to update map" ));
110+ if (!enif_make_map_put (env , error_map , enif_make_atom (env , "message" ),
111+ make_binary (env , result .error -> message ),
112+ & error_map )) {
113+ return enif_raise_exception (env ,
114+ make_binary (env , "failed to update map" ));
111115 }
112116
113117 term = enif_make_tuple2 (env , enif_make_atom (env , "error" ), error_map );
@@ -123,13 +127,13 @@ static ERL_NIF_TERM deparse_query(ErlNifEnv *env, int argc,
123127}
124128
125129static ERL_NIF_TERM scan_query (ErlNifEnv * env , int argc ,
126- const ERL_NIF_TERM argv []) {
130+ const ERL_NIF_TERM argv []) {
127131 ErlNifBinary query ;
128132 ERL_NIF_TERM term ;
129133
130134 if (argc == 1 && enif_inspect_binary (env , argv [0 ], & query )) {
131135 if (query .size >= MAX_QUERY_SIZE ) {
132- return enif_make_badarg (env );
136+ return query_too_long_error (env , query . size );
133137 }
134138
135139 // add one more byte for the null termination
@@ -145,25 +149,20 @@ static ERL_NIF_TERM scan_query(ErlNifEnv *env, int argc,
145149 if (result .error ) {
146150 ERL_NIF_TERM error_map = enif_make_new_map (env );
147151
148- if (!enif_make_map_put (
149- env ,
150- error_map ,
151- enif_make_atom (env , "message" ),
152- make_binary (env , result .error -> message ),
153- & error_map
154- )) {
155- return enif_raise_exception (env , make_binary (env , "failed to update map" ));
152+ if (!enif_make_map_put (env , error_map , enif_make_atom (env , "message" ),
153+ make_binary (env , result .error -> message ),
154+ & error_map )) {
155+ return enif_raise_exception (env ,
156+ make_binary (env , "failed to update map" ));
156157 }
157158
158- if (result .error -> cursorpos > 0 && !enif_make_map_put (
159- env ,
160- error_map ,
161- enif_make_atom (env , "cursorpos" ),
162- // drop the cursorpos by one, so it's zero-indexed
163- enif_make_int (env , result .error -> cursorpos - 1 ),
164- & error_map
165- )) {
166- return enif_raise_exception (env , make_binary (env , "failed to update map" ));
159+ if (result .error -> cursorpos > 0 &&
160+ !enif_make_map_put (env , error_map , enif_make_atom (env , "cursorpos" ),
161+ // drop the cursorpos by one, so it's zero-indexed
162+ enif_make_int (env , result .error -> cursorpos - 1 ),
163+ & error_map )) {
164+ return enif_raise_exception (env ,
165+ make_binary (env , "failed to update map" ));
167166 }
168167
169168 term = enif_make_tuple2 (env , enif_make_atom (env , "error" ), error_map );
@@ -179,10 +178,10 @@ static ERL_NIF_TERM scan_query(ErlNifEnv *env, int argc,
179178}
180179
181180static ErlNifFunc funcs [] = {
182- {"parse_query" , 1 , parse_query },
183- {"deparse_query" , 1 , deparse_query },
184- {"scan_query" , 1 , scan_query },
185- {"max_query_size" , 0 , max_query_size },
181+ {"parse_query" , 1 , parse_query },
182+ {"deparse_query" , 1 , deparse_query },
183+ {"scan_query" , 1 , scan_query },
184+ {"max_query_size" , 0 , max_query_size },
186185};
187186
188187ERL_NIF_INIT (Elixir .PgQuery .Parser , funcs , NULL , NULL , NULL , NULL )
0 commit comments