@@ -562,3 +562,84 @@ TEST_P(StringParameterBindingTest, SpecialCharactersRoundTrip)
562562
563563 STMT_OK (SQLFreeStmt (hstmt, SQL_CLOSE ));
564564}
565+
566+ TEST_F (StatementParameterBindingsTest, IntArrayInsertProcessesEverySet) {
567+ auto create_query = fromUTF8<PTChar>(
568+ " CREATE OR REPLACE TABLE param_array_insert (i Int32) engine MergeTree order by i" );
569+ STMT_OK (SQLExecDirect (hstmt, ptcharCast (create_query.data ()), SQL_NTS ));
570+ STMT_OK (SQLFreeStmt (hstmt, SQL_CLOSE ));
571+
572+ SQLINTEGER param[] = { 10 , 20 , 30 , 40 , 50 };
573+ SQLLEN param_ind[] = { 0 , 0 , 0 , 0 , 0 };
574+ SQLULEN params_processed = 0 ;
575+
576+ auto insert_query = fromUTF8<PTChar>(" INSERT INTO param_array_insert (i) VALUES (?)" );
577+ STMT_OK (SQLSetStmtAttr (hstmt, SQL_ATTR_PARAMSET_SIZE , (SQLPOINTER )lengthof (param), 0 ));
578+ STMT_OK (SQLSetStmtAttr (hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR , ¶ms_processed, 0 ));
579+ STMT_OK (SQLPrepare (hstmt, ptcharCast (insert_query.data ()), SQL_NTS ));
580+ STMT_OK (SQLBindParameter (
581+ hstmt,
582+ 1 ,
583+ SQL_PARAM_INPUT ,
584+ getCTypeFor<std::decay_t <decltype (param[0 ])>>(),
585+ SQL_INTEGER ,
586+ 0 ,
587+ 0 ,
588+ param,
589+ 0 ,
590+ param_ind));
591+
592+ // An INSERT returns no result sets, so nothing would prompt a caller to call SQLMoreResults:
593+ // this one call has to process the whole array.
594+ STMT_OK (SQLExecute (hstmt));
595+ ASSERT_EQ (params_processed, lengthof (param));
596+ STMT_OK (SQLFreeStmt (hstmt, SQL_CLOSE ));
597+
598+ auto select_query = fromUTF8<PTChar>(" SELECT i FROM param_array_insert ORDER BY i" );
599+ STMT_OK (SQLExecDirect (hstmt, ptcharCast (select_query.data ()), SQL_NTS ));
600+ for (std::size_t i = 0 ; i < lengthof (param); ++i) {
601+ SQLINTEGER value = 0 ;
602+ STMT_OK (SQLFetch (hstmt));
603+ STMT_OK (SQLGetData (hstmt, 1 , SQL_C_SLONG , &value, sizeof (value), nullptr ));
604+ ASSERT_EQ (value, param[i]) << " row " << i;
605+ }
606+ ASSERT_EQ (SQLFetch (hstmt), SQL_NO_DATA );
607+ STMT_OK (SQLFreeStmt (hstmt, SQL_CLOSE ));
608+ }
609+
610+ TEST_F (StatementParameterBindingsTest, IntArrayInsertReportsTheFailingSet) {
611+ // copy_id is derived from id with accurateCast, so an id that does not fit Int16 makes the
612+ // server reject that parameter set and nothing after it is sent.
613+ auto create_query = fromUTF8<PTChar>(
614+ " CREATE OR REPLACE TABLE param_array_error "
615+ " (id Int32, value String, copy_id Int16 DEFAULT accurateCast(id, 'Int16')) "
616+ " engine MergeTree order by id" );
617+ STMT_OK (SQLExecDirect (hstmt, ptcharCast (create_query.data ()), SQL_NTS ));
618+ STMT_OK (SQLFreeStmt (hstmt, SQL_CLOSE ));
619+
620+ SQLINTEGER ids[] = { 1 , 2 , 40000 , 4 , 5 };
621+ SQLLEN id_ind[] = { 0 , 0 , 0 , 0 , 0 };
622+ char values[][2 ] = { " a" , " b" , " c" , " d" , " e" };
623+ SQLLEN value_ind[] = { SQL_NTS , SQL_NTS , SQL_NTS , SQL_NTS , SQL_NTS };
624+ SQLULEN params_processed = 0 ;
625+ SQLUSMALLINT param_status[lengthof (ids)] = {};
626+
627+ auto insert_query = fromUTF8<PTChar>(" INSERT INTO param_array_error (id, value) VALUES (?, ?)" );
628+ STMT_OK (SQLSetStmtAttr (hstmt, SQL_ATTR_PARAMSET_SIZE , (SQLPOINTER )lengthof (ids), 0 ));
629+ STMT_OK (SQLSetStmtAttr (hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR , ¶ms_processed, 0 ));
630+ STMT_OK (SQLSetStmtAttr (hstmt, SQL_ATTR_PARAM_STATUS_PTR , param_status, 0 ));
631+ STMT_OK (SQLPrepare (hstmt, ptcharCast (insert_query.data ()), SQL_NTS ));
632+ STMT_OK (SQLBindParameter (hstmt, 1 , SQL_PARAM_INPUT , SQL_C_SLONG , SQL_INTEGER , 0 , 0 , ids, 0 , id_ind));
633+ STMT_OK (SQLBindParameter (hstmt, 2 , SQL_PARAM_INPUT , SQL_C_CHAR , SQL_VARCHAR , 255 , 0 , values, sizeof (values[0 ]), value_ind));
634+
635+ ASSERT_EQ (SQLExecute (hstmt), SQL_ERROR );
636+
637+ // The count includes the set that failed, and the status array says which one.
638+ ASSERT_EQ (params_processed, 3u );
639+ ASSERT_EQ (param_status[0 ], SQL_PARAM_SUCCESS );
640+ ASSERT_EQ (param_status[1 ], SQL_PARAM_SUCCESS );
641+ ASSERT_EQ (param_status[2 ], SQL_PARAM_ERROR );
642+ ASSERT_EQ (param_status[3 ], SQL_PARAM_UNUSED );
643+ ASSERT_EQ (param_status[4 ], SQL_PARAM_UNUSED );
644+ STMT_OK (SQLFreeStmt (hstmt, SQL_CLOSE ));
645+ }
0 commit comments