Simple encapsulation of MySQL, learning managed-Based C ++ Development
After a long time, I understood some things and had a hard time talking about them.
1. background.
Recently I am writing a bit of trial code. I need to make a simple prototype to verify that my ideas are correct. This prototype consists of a database (MySQL) and a front-end interface.
MySQL table/test data has been created.
On the front-end interface, I accidentally used C ++, And the CLR interface was chosen by the ghost. (I finally figured out the CLR pointer ^ for a long time yesterday and called MySQL through VC. Solve the character set problem .)
Today, I wanted to use C. However, I was a little unwilling. I wrote it again to check whether the managed C ++ code is different. So I rewritten the code called MySQL yesterday and tried to encapsulate it.
2. problems encountered.
For traditional SQL calls, bind outputs variables, executes SQL statements, and uses output variables.
For example, the call I imagined is as follows:
String ^ values; int myintresult1; double mydoubleresult1; values (1, stringtype, mystringresult1); values (2, inttype, & myintresult1); values (3, doubletype, & mydoubleresult1 ); mysql_select (3, "select 'hello, this is string', 12, 12.345"); // next mystringresult1 equals 'hello, this is string ', // myintresult1 equals 12, and mydoubleresult1 equals 12.345
Naturally, it encapsulates a MySQL operation class.
public ref class tsql{ ConnectDB(xxx) DisConnectDB(xxx) BindVar(xxx); Select(xxx)…}
When implementing bindvar, the simplest thing is to create an array, register the bound variables, and then instantiate and assign values when implementing select.
It is easy to implement unmanaged code.
void *m_pArray[MAX_VARS]; void mysql_bind_var(int a,int b,void *pv){ M_pArray[a]=pv;} void mysql_select(int a,char *s){ *(int*)(m_pArray[0])=12; *(double*)(m_pArray[1])=12.34; Strcpy((char*)(m_pArray[2]),”helloxxx”);}
Oh, that is, record an address in BIND, and put the obtained result directly in select.
Can managed code be implemented? The result is no.
This problem is summarized to indicate whether managed variables can be instantiated in other places than stack passing parameters, that is, there cannot be pointers pointing to managed pointers. (Managed variables can be initialized by managed pointers, and managed pointers cannot be recorded beyond their lifecycles)
That is:
Example 1: normal gcnew instantiation
Void test001 () {string ^ Foo; Foo = gcnew string ("hello"); // correct! Foo = "hello", normal instantiation}
Example 2: instantiated in function call
Void test002_sub (string ^ % pstring) {pstring = gcnew string ("hello");} void test002 () {string ^ Foo; test002_sub (FOO); // correct! Foo = "hello", which is instantiated in the stack parameter .}
Example 3: The parameter is instantiated in a place other than the stack parameter.
Void test003_setpointer (string ^ % pstring, recordvar ^ % precord) {// record the pstring address in precord} void test003_initpointer (recordvar ^ % precord) {// initialize and assign values to the pstring of the precord .} Void test003 () {string ^ Foo; test003_setpointer (Foo, record); // There is no way to make a record to record the foo address test003_initpointer (record ); // then use record directly to initialize Foo // hopefully think that foo is available at this time}
I tried a variety of methods, including system: Object packaging, interior_ptr, and so on.
Later, I suddenly realized that this is because it cannot guarantee security, and of course it is not allowed by the hosted code.
3. cause:
If you can record the pointer that hosts the pointer, it means that the hosted pointer has an alias. When the managed pointer fails, how should the managed pointer be self-contained?
If a pointer to the managed pointer is allowed, the managed pointer should not be a stack object, but an object in the managed heap. Otherwise, the content pointed to by the pointer pointing to the managed pointer may be forced to be illegal (when the program runs out of the scope of the managed pointer, the managed pointer will become invalid, the pointer pointing to this pointer must also be invalid ).
This explains why there are no pointers to managed pointers and why interior_ptr can only be on the stack.
Because the life cycle of interior_ptr should be the same as that of its program execution, to ensure that its life cycle is equal to that of its program execution, it cannot be assigned to other variables.
In other words, in managed mode, a variable cannot be changed outside its lifecycle. (It's too easy, even if I knew it at first, it would be bypassed)
4. Managed mode code:
For security reasons, pointer hosting is disabled.
So, the simplest thing is not to let the caller's hosted variable out of the "Caller" field of view.
Changed to this mode:
OutParamo1,o2,o3;Int iResult1;String^sResult1;Double dResult1; Sql_select(“select xx ,xx ,xx from xxx where xxx “, o1,o2,o3);iResult1 = o1;sResult1= o2;dResult1 =o3; sql_select(String^ sqlStmt,…array<System::Object^>^pOutParams){ OutParam ^po; for(i=0;i<pOutParams->Length;i++){ po= (OutParam^)pOutParams[i]; if (i == 1) po->result= gcnew String(“hello”); if (i == 2) po->result= gcnew int(12); if (i == 3) po->result= gcnew double(12.34); }} public ref class OutParam{public: OutParam(){}; operator int(){ return (int)result; } operator System::String^(){ return (System::String^)result; } operator double(){ return (double)result; } System::Object ^result; }