[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Конвертация внутреннего представления переменных в Tcl



Hello!

On Thursday 08 October 2009 22:57:38 Victor Wagner wrote:
> On 2009.10.08 at 22:38:55 +0400, Alexey Pechnikov wrote:
> > > (благо, и поле typePtr в Tcl_Obj, и поле name в Tcl_ObjType -
> > > документировано)
> > 
> > Ситуация как раз в том, что апстрим sqlite делает именно проверку по 
> > obj->typePtr->name 
> 
> А вот тут НЕ НАДО делать проверку. Благо требуемый тип известен.
> Надо не проверять, а пытаться преобразовать данные к требуемому типу.
> И ругаться только если не получилось. 

Насчет "требуемый известен" это не совсем так. Но при работе в шелле эскулайт 
или тикля при введении цифр оно считается числом, а вот из тиклевского скрипта
- строкой. Потому разумно всегда полагать строку цифр - числом. И только если 
оно не число, считать это строкой.

Конечно, лишнии операции конвертации приходится делать, по сравнению с
тупой проверкой текущего представления переменной. Но конвертация в int
и double не особенно накладная вещь, это же не строки преобразовывать. Зато
работает корректно, не зависимо от того, существует ли заранее для тиклевской
переменной численное представление или нет.

> Соответствено, Tcl_GetWideIntFromObj.
> 
> При этом таблица преобразований должна быть не тикловая внутренняя,
> поскольку  никто не обещал, что завтра внутреннее представление 
> integer не поменяют на несовместимое с нужным тебе, а своя собственная,
> использующая для преобразования Tcl_Get*FromObj. Поскольку у них тип
> результата документирован.

Собственно, из патча видно, как есть в апстриме и что получилось у меня.
Я понимаю, что апстримовский код быстрее, еще бы он работал корректно...
Оптимизация  pVar->typePtr->name[0]=='b' при использовании функций 
Tcl_Get...FromObj вряд ли оправдана, но и не помешает.

--- tclsqlite.c.old     2009-09-05 00:37:43.000000000 +0400                                                                         
+++ tclsqlite.c 2009-10-08 23:43:51.000000000 +0400                                                                                 
@@ -754,26 +754,18 @@                                                                                                               
   }else{                                                                                                                           
     Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);                                                                                   
     int n;                                                                                                                         
+    Tcl_WideInt v;                                                                                                                 
+    double r;                                                                                                                      
     u8 *data;                                                                                                                      
-    char *zType = pVar->typePtr ? pVar->typePtr->name : "";                                                                        
-    char c = zType[0];                                                                                                             
-    if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){                                                                
+    if( pVar->typePtr && pVar->typePtr->name[0]=='b' && strcmp(pVar->typePtr->name,"bytearray")==0 && pVar->bytes==0 ){            
       /* Only return a BLOB type if the Tcl variable is a bytearray and                                                            
       ** has no string representation. */                                                                                          
       data = Tcl_GetByteArrayFromObj(pVar, &n);                                                                                    
       sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT);                                                                     
-    }else if( c=='b' && strcmp(zType,"boolean")==0 ){                                                                              
-      Tcl_GetIntFromObj(0, pVar, &n);                                                                                              
-      sqlite3_result_int(context, n);                                                                                              
-    }else if( c=='d' && strcmp(zType,"double")==0 ){                                                                               
-      double r;                                                                                                                    
-      Tcl_GetDoubleFromObj(0, pVar, &r);                                                                                           
-      sqlite3_result_double(context, r);                                                                                           
-    }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||                                                                            
-          (c=='i' && strcmp(zType,"int")==0) ){                                                                                    
-      Tcl_WideInt v;                                                                                                               
-      Tcl_GetWideIntFromObj(0, pVar, &v);                                                                                          
+    }else if( TCL_OK == Tcl_GetWideIntFromObj(0, pVar, &v)){                                                                       
       sqlite3_result_int64(context, v);                                                                                            
+    }else if( TCL_OK == Tcl_GetDoubleFromObj(0, pVar, &r)){                                                                        
+      sqlite3_result_double(context, r);                                                                                           
     }else{                                                                                                                         
       data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);                                                                      
       sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT);                                                             
@@ -1629,6 +1621,9 @@                                                                                                               
     SqlPreparedStmt *pPreStmt;  /* Pointer to a prepared statement */                                                              
     int rc2;

+    Tcl_ObjType *tclWideIntType = Tcl_GetObjType("wideint");
+    Tcl_ObjType *tclDoubleType = Tcl_GetObjType("double");
+
     if( choice==DB_EVAL ){
       if( objc<3 || objc>5 ){
         Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?");
@@ -1744,10 +1739,10 @@
           if( pVar ){
             int n;
             u8 *data;
-            char *zType = pVar->typePtr ? pVar->typePtr->name : "";
-            char c = zType[0];
+            double r;
+            Tcl_WideInt v;
             if( zVar[0]=='@' ||
-               (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){
+               ( pVar->typePtr && pVar->typePtr->name[0]=='b' && strcmp(pVar->typePtr->name,"bytearray")==0 && pVar->bytes==0) ){
               /* Load a BLOB type if the Tcl variable is a bytearray and
               ** it has no string representation or the host
               ** parameter name begins with "@". */
@@ -1755,18 +1750,10 @@
               sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
               Tcl_IncrRefCount(pVar);
               apParm[nParm++] = pVar;
-            }else if( c=='b' && strcmp(zType,"boolean")==0 ){
-              Tcl_GetIntFromObj(interp, pVar, &n);
-              sqlite3_bind_int(pStmt, i, n);
-            }else if( c=='d' && strcmp(zType,"double")==0 ){
-              double r;
-              Tcl_GetDoubleFromObj(interp, pVar, &r);
-              sqlite3_bind_double(pStmt, i, r);
-            }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
-                  (c=='i' && strcmp(zType,"int")==0) ){
-              Tcl_WideInt v;
-              Tcl_GetWideIntFromObj(interp, pVar, &v);
+            }else if( TCL_OK == Tcl_GetWideIntFromObj(interp, pVar, &v)) {
               sqlite3_bind_int64(pStmt, i, v);
+            }else if( TCL_OK == Tcl_GetDoubleFromObj(interp, pVar, &r)) {
+              sqlite3_bind_double(pStmt, i, r);
             }else{
               data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
               sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);


Best regards, Alexey Pechnikov.
http://pechnikov.tel/


Reply to: