Re: [Cppcms-users] cppdb::statement copy and assign
Brought to you by:
artyom-beilis
From: CN <cn...@fa...> - 2015-11-12 09:53:16
|
Because the SQL is dynamically generated, I called cppdb::session::create_prepared_uncached_statement() instead of cppdb::session::create_statement(). The old version that gave me trouble follows: void db_conn_init(cppdb::session &db_session) { db_session << "SET NAMES 'UTF8'" << cppdb::exec; db_session << "SET TIME ZONE 'UTC'" << cppdb::exec; } cppdb::statement create(cppdb::session &se,std::string const &table) { cppcms::json::array keys,values; //Feed elements to keys and values here. std::vector<std::string> set_values; std::string column_list=utils::make_column_list(values,set_values); std::vector<std::string> where_values; std::string sql="UPDATE "+table+" SET "+column_list+utils::make_where(keys,where_values); //"sql" now becomes "UPDATE t SET c2=? WHERE c1=? AND c2=?" cppdb::statement st=se.create_prepared_uncached_statement(sql); size_t set_values_size=set_values.size(); for(size_t i=0;i < set_values_size;++i){ if(set_values[i].empty()) st.bind_null(i+1); else st.bind(i+1,set_values[i]); } for(size_t i=0,n=where_values.size();i < n;++i){ if(where_values[i].empty()) st.bind_null(set_values_size+i+1); else st.bind(set_values_size+i+1,where_values[i]); } return st; } Please note that cppdb::statement create(cppdb::session &se,std::string const &table) is a function. It is not a member function of a class. void my_class::use() { cppdb::session se("postgresql:@pool_size=5;dbname=db2;user=user2;password=xxx",db_conn_init); std::string table="t"; cppdb::statement st=create(se,"t"); cppdb::transaction tx(se); st.exec(); //Weird error occurs here. //Do more SQL here like this: //se << "INSERT INTO ..."; tx.commit(); } I do not have trouble with this new version: void my_class::use() { cppdb::session se("postgresql:@pool_size=5;dbname=db2;user=user2;password=xxx",db_conn_init); std::string table="t"; cppcms::json::array keys,values; //Feed elements to keys and values here. std::vector<std::string> set_values; std::string column_list=utils::make_column_list(values,set_values); std::vector<std::string> where_values; std::string sql="UPDATE "+table+" SET "+column_list+utils::make_where(keys,where_values); //"sql" now becomes "UPDATE t SET c2=? WHERE c1=? AND c2=?" cppdb::statement st=se.create_prepared_uncached_statement(sql); size_t set_values_size=set_values.size(); for(size_t i=0;i < set_values_size;++i){ if(set_values[i].empty()) st.bind_null(i+1); else st.bind(i+1,set_values[i]); } for(size_t i=0,n=where_values.size();i < n;++i){ if(where_values[i].empty()) st.bind_null(set_values_size+i+1); else st.bind(set_values_size+i+1,where_values[i]); } cppdb::transaction tx(se); st.exec(); //Do more SQL here like this: //se << "INSERT INTO ..."; tx.commit(); } Best Regards, CN On Thu, Nov 12, 2015, at 04:22 PM, CN wrote: > Thank you for the reply! > > Having received your message, I went back and study frontend.* and > backend.* of cppdb source code trying to understand more about it. > According to my findings so far, instances of cppdb::statement in > backend indeed are reference counted, meaning to me that these objects > will not be destroyed as long as they are still referenced. > > But I can only go that deep into cppdb source. Because my original > troublesome code actually uses uncached statement but I do not fully > understand cppdb's statement cache mechanism, I begin to suspect this > part of cppdb. > > I know this is not professional attitude, but the simplified version of > my troublesome code follows: > > cppdb::statement create(cppdb::session &se) > { > cppdb::statement st=se.create_prepared_uncached_statement( > "UPDATE t SET c2=? WHERE c1=? AND c2=?") > << 'xx' << 2; > return st; > } > > void use() > { > cppdb::session se("connection params"); > cppdb::statement st=create(se); > cppdb::transaction tx(se); > st.exec(); //Weird error occurs here. > //Do more SQL here like this: > //se << "INSERT INTO ..."; > tx.commit(); > } > > Note that the data type of t.c2 is INTEGER. > > And the PostgreSQL error log follows: > > 2015-10-31 14:20:42 CST ERROR: invalid input syntax for integer: > "cppdb_psqlstmt_17" > 2015-10-31 14:20:42 CST STATEMENT: UPDATE t SET c2=$1 WHERE c1=$2 AND > c2=$3 > 2015-10-31 19:46:26 CST ERROR: invalid input syntax for integer: "" > 2015-10-31 19:46:26 CST STATEMENT: UPDATE t SET c2=$1 WHERE c1=$2 AND > c2=$3 > 2015-10-31 22:42:24 CST ERROR: invalid input syntax for integer: "" > 2015-10-31 22:42:24 CST STATEMENT: UPDATE t SET c2=$1 WHERE c1=$2 AND > c2=$3 > 2015-10-31 22:55:28 CST ERROR: invalid input syntax for integer: "!" > 2015-10-31 22:55:28 CST STATEMENT: UPDATE t SET c2=$1 WHERE c1=$2 AND > c2=$3 > > As one might notice: How could I bind "cppdb_psqlstmt_17" to > cppdb::statement's parameters? > PostgreSQL complained weird arguments passed to c2 when the same > cppdb::statement::exec() was called repeatedly. > > Any idea? Please! > > Best Regards, > CN > > > On Thu, Nov 12, 2015, at 12:47 AM, Artyom Beilis wrote: > > Actually you are mistaken. > > > > cppdb::statement, cppdb::session and cppdb::result keep the reference to > > underlying > > backed object representing them. > > > > See: > > http://cppcms.com/sql/cppdb/classcppdb_1_1statement.html#adc5ddc1e8df9248b74692990cffe40cf > > > > So copy is totally valid and you can use it this way without problems. > > > > Actually statement would also keep a track of the session and result of > > statement and session as > > well. > > > > So it is correct way to do things. > > > > Of course it is bad idea to start using copies of came cppdb::statement > > from two > > different locations simultaneously. > > > > So look for the problem in some other place. > > > > Artyom > > > > > > > Hi! > > > > > > I recently made a mistake by doing this: > > > > > > cppdb::statement create(){ > > > cppdb::session se("connect parameters"); > > > cppdb::statement st=se << "SELECT * FROM t"; > > > return st; > > > } > > > > > > void use(){ > > > cppdb::statement st=create(); > > > st.query(); > > > } > > > > > > Very weird errors happens to st.query(). > > > It took me quite some time to pin point the bug. After that, I re-read > > > the comments in cppdb/cppdb/frontend.h and I believe they confirm my > > > conclusion: > > > > > > The problem here, I believe, is that cppdb::statement object is already > > > destroyed before st.query() is executed. > > > > > > I am writing this note here in order to remind myself of avoiding such > > > practice. Hopefully no one else will make the same mistake as I did! > > > > > > Meanwhile, I suspect it will be better off > > > > > > (a) either to remove the cppdb::statement copy and assignment methods > > > from cppdb source altogether > > > (b) or to make cppdb::statement non-copyable > > > > > > I have a feeling that these two methods serve only as a trap. > > > Yes? No? > > > > > > Best Regards, > > > CN > > > > > > -- > > > http://www.fastmail.com - Access all of your messages and folders > > > wherever you are > > > > > > > > > ------------------------------------------------------------------------------ > > > _______________________________________________ > > > Cppcms-users mailing list > > > Cpp...@li... > > > https://lists.sourceforge.net/lists/listinfo/cppcms-users > > > > > > > ------------------------------------------------------------------------------ > > _______________________________________________ > > Cppcms-users mailing list > > Cpp...@li... > > https://lists.sourceforge.net/lists/listinfo/cppcms-users > > -- > http://www.fastmail.com - Access your email from home and the web > > > ------------------------------------------------------------------------------ > _______________________________________________ > Cppcms-users mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppcms-users -- http://www.fastmail.com - Access all of your messages and folders wherever you are |