@@ -156,6 +156,31 @@ make_error_tuple(ErlNifEnv* env, const char* reason)
156156 return enif_make_tuple2 (env , make_atom (env , "error" ), make_atom (env , reason ));
157157}
158158
159+ static ERL_NIF_TERM
160+ make_bind_error (ErlNifEnv * env , ERL_NIF_TERM message , ERL_NIF_TERM argument )
161+ {
162+ assert (env );
163+ assert (message );
164+
165+ ERL_NIF_TERM error_struct = enif_make_new_map (env );
166+
167+ enif_make_map_put (
168+ env ,
169+ error_struct ,
170+ make_atom (env , "message" ),
171+ message ,
172+ & error_struct );
173+
174+ enif_make_map_put (
175+ env ,
176+ error_struct ,
177+ make_atom (env , "argument" ),
178+ argument ,
179+ & error_struct );
180+
181+ return error_struct ;
182+ }
183+
159184static ERL_NIF_TERM
160185make_binary (ErlNifEnv * env , const void * bytes , unsigned int size )
161186{
@@ -173,6 +198,20 @@ make_binary(ErlNifEnv* env, const void* bytes, unsigned int size)
173198 return term ;
174199}
175200
201+ /**
202+ * @brief Makes a string for an error message.
203+ *
204+ * @note Do not use this for untrusted binaries. Intention here is to only use
205+ * strings assembled here.
206+ *
207+ * @return The binary.
208+ */
209+ static ERL_NIF_TERM
210+ make_message (ErlNifEnv * env , const char * str )
211+ {
212+ return make_binary (env , str , strlen (str ));
213+ }
214+
176215static ERL_NIF_TERM
177216make_sqlite3_error_tuple (ErlNifEnv * env , int rc , sqlite3 * db )
178217{
@@ -408,9 +447,10 @@ exqlite_prepare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
408447 return make_ok_tuple (env , result );
409448}
410449
411- static int
450+ static ERL_NIF_TERM
412451bind (ErlNifEnv * env , const ERL_NIF_TERM arg , sqlite3_stmt * statement , int index )
413452{
453+ int rc ;
414454 int the_int ;
415455 ErlNifSInt64 the_long_int ;
416456 double the_double ;
@@ -419,45 +459,125 @@ bind(ErlNifEnv* env, const ERL_NIF_TERM arg, sqlite3_stmt* statement, int index)
419459 int arity ;
420460 const ERL_NIF_TERM * tuple ;
421461
422- if (enif_get_int (env , arg , & the_int )) {
423- return sqlite3_bind_int (statement , index , the_int );
462+ if (enif_get_int64 (env , arg , & the_long_int )) {
463+ rc = sqlite3_bind_int64 (statement , index , the_long_int );
464+ if (rc == SQLITE_OK ) {
465+ return make_atom (env , "ok" );
466+ }
467+
468+ return enif_raise_exception (
469+ env ,
470+ make_bind_error (
471+ env ,
472+ make_message (env , "Failed to bind argument as 64 bit integer" ),
473+ arg ));
424474 }
425475
426- if (enif_get_int64 (env , arg , & the_long_int )) {
427- return sqlite3_bind_int64 (statement , index , the_long_int );
476+ if (enif_get_int (env , arg , & the_int )) {
477+ rc = sqlite3_bind_int (statement , index , the_int );
478+ if (rc == SQLITE_OK ) {
479+ return make_atom (env , "ok" );
480+ }
481+
482+ return enif_raise_exception (
483+ env ,
484+ make_bind_error (
485+ env ,
486+ make_message (env , "Failed to bind argument as integer" ),
487+ arg ));
428488 }
429489
430490 if (enif_get_double (env , arg , & the_double )) {
431- return sqlite3_bind_double (statement , index , the_double );
491+ rc = sqlite3_bind_double (statement , index , the_double );
492+ if (rc == SQLITE_OK ) {
493+ return make_atom (env , "ok" );
494+ }
495+
496+ return enif_raise_exception (
497+ env ,
498+ make_bind_error (
499+ env ,
500+ make_message (env , "Failed to bind argument as double" ),
501+ arg ));
432502 }
433503
434504 if (enif_get_atom (env , arg , the_atom , sizeof (the_atom ), ERL_NIF_LATIN1 )) {
435505 if (0 == strcmp ("undefined" , the_atom ) || 0 == strcmp ("nil" , the_atom )) {
436- return sqlite3_bind_null (statement , index );
506+ rc = sqlite3_bind_null (statement , index );
507+ if (rc == SQLITE_OK ) {
508+ return make_atom (env , "ok" );
509+ }
510+
511+ return enif_raise_exception (
512+ env ,
513+ make_bind_error (
514+ env ,
515+ make_message (env , "Failed to bind argument as null" ),
516+ arg ));
437517 }
438518
439- return sqlite3_bind_text (statement , index , the_atom , strlen (the_atom ), SQLITE_TRANSIENT );
519+ rc = sqlite3_bind_text (statement , index , the_atom , strlen (the_atom ), SQLITE_TRANSIENT );
520+ if (rc == SQLITE_OK ) {
521+ return make_atom (env , "ok" );
522+ }
523+
524+ return enif_raise_exception (
525+ env ,
526+ make_bind_error (
527+ env ,
528+ make_message (env , "Failed to bind argument as text" ),
529+ arg ));
440530 }
441531
442532 if (enif_inspect_iolist_as_binary (env , arg , & the_blob )) {
443- return sqlite3_bind_text (statement , index , (char * )the_blob .data , the_blob .size , SQLITE_TRANSIENT );
533+ rc = sqlite3_bind_text (statement , index , (char * )the_blob .data , the_blob .size , SQLITE_TRANSIENT );
534+ if (rc == SQLITE_OK ) {
535+ return make_atom (env , "ok" );
536+ }
537+
538+ return enif_raise_exception (
539+ env ,
540+ make_bind_error (
541+ env ,
542+ make_message (env , "Failed to bind argument as text" ),
543+ arg ));
444544 }
445545
446546 if (enif_get_tuple (env , arg , & arity , & tuple )) {
447547 if (arity != 2 ) {
448- return -1 ;
548+ return enif_raise_exception (
549+ env ,
550+ make_bind_error (
551+ env ,
552+ make_message (env , "Failed to bind argument as blob" ),
553+ arg ));
449554 }
450555
451556 if (enif_get_atom (env , tuple [0 ], the_atom , sizeof (the_atom ), ERL_NIF_LATIN1 )) {
452557 if (0 == strcmp ("blob" , the_atom )) {
453558 if (enif_inspect_iolist_as_binary (env , tuple [1 ], & the_blob )) {
454- return sqlite3_bind_blob (statement , index , the_blob .data , the_blob .size , SQLITE_TRANSIENT );
559+ rc = sqlite3_bind_blob (statement , index , the_blob .data , the_blob .size , SQLITE_TRANSIENT );
560+ if (rc == SQLITE_OK ) {
561+ return make_atom (env , "ok" );
562+ }
563+
564+ return enif_raise_exception (
565+ env ,
566+ make_bind_error (
567+ env ,
568+ make_message (env , "Failed to bind argument as blob" ),
569+ arg ));
455570 }
456571 }
457572 }
458573 }
459574
460- return -1 ;
575+ return enif_raise_exception (
576+ env ,
577+ make_bind_error (
578+ env ,
579+ make_message (env , "Failed to bind argument" ),
580+ arg ));
461581}
462582
463583///
@@ -502,19 +622,14 @@ exqlite_bind(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
502622 list = argv [2 ];
503623 for (unsigned int i = 0 ; i < argument_list_length ; i ++ ) {
504624 enif_get_list_cell (env , list , & head , & tail );
505- int rc = bind (env , head , statement -> statement , i + 1 );
506- if (rc == -1 ) {
507- return enif_make_tuple2 (
508- env ,
509- make_atom (env , "error" ),
510- enif_make_tuple2 (
511- env ,
512- make_atom (env , "wrong_type" ),
513- head ));
514- }
625+ ERL_NIF_TERM result = bind (env , head , statement -> statement , i + 1 );
515626
516- if (rc != SQLITE_OK ) {
517- return make_sqlite3_error_tuple (env , rc , conn -> db );
627+ // We are going to ignore this, we have to pass it.
628+ ERL_NIF_TERM reason ;
629+
630+ // Bind will set an exception if anything happens during that phase.
631+ if (enif_has_pending_exception (env , & reason )) {
632+ return make_error_tuple (env , "failed_to_bind_argument" );
518633 }
519634
520635 list = tail ;
0 commit comments