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: