4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** Code for testing all sorts of SQLite interfaces. This code
13 ** is not included in the SQLite library.
17 #if defined(INCLUDE_SQLITE_TCL_H)
18 # include "sqlite_tcl.h"
23 /* Solely for the UNUSED_PARAMETER() macro. */
24 #include "sqliteInt.h"
26 #ifdef SQLITE_ENABLE_RTREE
28 typedef struct BoxGeomCtx BoxGeomCtx
;
34 typedef struct BoxQueryCtx BoxQueryCtx
;
40 static void testDelUser(void *pCtx
){
41 BoxGeomCtx
*p
= (BoxGeomCtx
*)pCtx
;
42 Tcl_EvalObjEx(p
->interp
, p
->pScript
, 0);
43 Tcl_DecrRefCount(p
->pScript
);
47 static int invokeTclGeomCb(
49 sqlite3_rtree_geometry
*p
,
51 sqlite3_rtree_dbl
*aCoord
56 BoxGeomCtx
*pCtx
= (BoxGeomCtx
*)p
->pContext
;
57 Tcl_Interp
*interp
= pCtx
->interp
;
65 pScript
= Tcl_DuplicateObj(pCtx
->pScript
);
66 Tcl_IncrRefCount(pScript
);
67 Tcl_ListObjAppendElement(interp
, pScript
, Tcl_NewStringObj(zName
,-1));
69 sqlite3_snprintf(sizeof(aPtr
)-1, aPtr
, "%p", (void*)p
->pContext
);
70 Tcl_ListObjAppendElement(interp
, pScript
, Tcl_NewStringObj(aPtr
,-1));
72 pParam
= Tcl_NewObj();
73 for(ii
=0; ii
<p
->nParam
; ii
++){
74 Tcl_ListObjAppendElement(
75 interp
, pParam
, Tcl_NewDoubleObj(p
->aParam
[ii
])
78 Tcl_ListObjAppendElement(interp
, pScript
, pParam
);
80 pCoord
= Tcl_NewObj();
81 for(ii
=0; ii
<nCoord
; ii
++){
82 Tcl_ListObjAppendElement(interp
, pCoord
, Tcl_NewDoubleObj(aCoord
[ii
]));
84 Tcl_ListObjAppendElement(interp
, pScript
, pCoord
);
86 sqlite3_snprintf(sizeof(aPtr
)-1, aPtr
, "%p", (void*)p
);
87 Tcl_ListObjAppendElement(interp
, pScript
, Tcl_NewStringObj(aPtr
,-1));
89 rc
= Tcl_EvalObjEx(interp
, pScript
, 0);
96 pRes
= Tcl_GetObjResult(interp
);
97 if( Tcl_ListObjGetElements(interp
, pRes
, &nObj
, &aObj
) ) return TCL_ERROR
;
99 const char *zCmd
= Tcl_GetString(aObj
[0]);
100 if( 0==sqlite3_stricmp(zCmd
, "zero") ){
104 else if( 0==sqlite3_stricmp(zCmd
, "user") ){
105 if( p
->pUser
|| p
->xDelUser
){
108 BoxGeomCtx
*pBGCtx
= sqlite3_malloc(sizeof(BoxGeomCtx
));
112 pBGCtx
->interp
= interp
;
113 pBGCtx
->pScript
= Tcl_DuplicateObj(pRes
);
114 Tcl_IncrRefCount(pBGCtx
->pScript
);
115 Tcl_ListObjReplace(interp
, pBGCtx
->pScript
, 0, 1, 0, 0);
116 p
->pUser
= (void*)pBGCtx
;
117 p
->xDelUser
= testDelUser
;
121 else if( 0==sqlite3_stricmp(zCmd
, "user_is_zero") ){
122 if( p
->pUser
|| p
->xDelUser
) rc
= SQLITE_ERROR
;
131 # EVIDENCE-OF: R-00693-36727 The legacy xGeom callback is invoked with
134 # EVIDENCE-OF: R-50437-53270 The first argument is a pointer to an
135 # sqlite3_rtree_geometry structure which provides information about how
136 # the SQL function was invoked.
138 # EVIDENCE-OF: R-00090-24248 The third argument, aCoord[], is an array
139 # of nCoord coordinates that defines a bounding box to be tested.
141 # EVIDENCE-OF: R-28207-40885 The last argument is a pointer into which
142 # the callback result should be written.
146 sqlite3_rtree_geometry
*p
, /* R-50437-53270 */
147 int nCoord
, /* R-02424-24769 */
148 sqlite3_rtree_dbl
*aCoord
, /* R-00090-24248 */
149 int *pRes
/* R-28207-40885 */
153 if( p
->nParam
!=nCoord
){
154 invokeTclGeomCb("box", p
, nCoord
, aCoord
);
157 if( invokeTclGeomCb("box", p
, nCoord
, aCoord
) ) return SQLITE_ERROR
;
159 for(ii
=0; ii
<nCoord
; ii
+=2){
160 if( aCoord
[ii
]>p
->aParam
[ii
+1] || aCoord
[ii
+1]<p
->aParam
[ii
] ){
173 static int SQLITE_TCLAPI
register_box_geom(
177 Tcl_Obj
*CONST objv
[]
179 extern int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
180 extern const char *sqlite3ErrName(int);
186 Tcl_WrongNumArgs(interp
, 1, objv
, "DB SCRIPT");
189 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
191 pCtx
= (BoxGeomCtx
*)ckalloc(sizeof(BoxGeomCtx
*));
192 pCtx
->interp
= interp
;
193 pCtx
->pScript
= Tcl_DuplicateObj(objv
[2]);
194 Tcl_IncrRefCount(pCtx
->pScript
);
196 sqlite3_rtree_geometry_callback(db
, "box", box_geom
, (void*)pCtx
);
198 sqlite3_snprintf(64, aPtr
, "%p", (void*)pCtx
);
199 Tcl_SetObjResult(interp
, Tcl_NewStringObj(aPtr
, -1));
203 static int box_query(sqlite3_rtree_query_info
*pInfo
){
204 const char *azParentWithin
[] = {"not", "partly", "fully", 0};
205 BoxQueryCtx
*pCtx
= (BoxQueryCtx
*)pInfo
->pContext
;
206 Tcl_Interp
*interp
= pCtx
->interp
;
213 pEval
= Tcl_DuplicateObj(pCtx
->pScript
);
214 Tcl_IncrRefCount(pEval
);
216 Tcl_IncrRefCount(pArg
);
220 Tcl_IncrRefCount(pTmp
);
221 for(ii
=0; ii
<pInfo
->nParam
; ii
++){
222 Tcl_Obj
*p
= Tcl_NewDoubleObj(pInfo
->aParam
[ii
]);
223 Tcl_ListObjAppendElement(interp
, pTmp
, p
);
225 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("aParam", -1));
226 Tcl_ListObjAppendElement(interp
, pArg
, pTmp
);
227 Tcl_DecrRefCount(pTmp
);
231 Tcl_IncrRefCount(pTmp
);
232 for(ii
=0; ii
<pInfo
->nCoord
; ii
++){
233 Tcl_Obj
*p
= Tcl_NewDoubleObj(pInfo
->aCoord
[ii
]);
234 Tcl_ListObjAppendElement(interp
, pTmp
, p
);
236 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("aCoord", -1));
237 Tcl_ListObjAppendElement(interp
, pArg
, pTmp
);
238 Tcl_DecrRefCount(pTmp
);
242 Tcl_IncrRefCount(pTmp
);
243 for(ii
=0; ii
<=pInfo
->mxLevel
; ii
++){
244 Tcl_Obj
*p
= Tcl_NewIntObj((int)pInfo
->anQueue
[ii
]);
245 Tcl_ListObjAppendElement(interp
, pTmp
, p
);
247 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("anQueue", -1));
248 Tcl_ListObjAppendElement(interp
, pArg
, pTmp
);
249 Tcl_DecrRefCount(pTmp
);
252 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("iLevel", -1));
253 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewIntObj(pInfo
->iLevel
));
256 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("mxLevel", -1));
257 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewIntObj(pInfo
->mxLevel
));
260 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("iRowid", -1));
261 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewWideIntObj(pInfo
->iRowid
));
264 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("rParentScore", -1));
265 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewDoubleObj(pInfo
->rParentScore
));
268 assert( pInfo
->eParentWithin
==0
269 || pInfo
->eParentWithin
==1
270 || pInfo
->eParentWithin
==2
272 Tcl_ListObjAppendElement(interp
, pArg
, Tcl_NewStringObj("eParentWithin", -1));
273 Tcl_ListObjAppendElement(interp
, pArg
,
274 Tcl_NewStringObj(azParentWithin
[pInfo
->eParentWithin
], -1)
277 Tcl_ListObjAppendElement(interp
, pEval
, pArg
);
278 rc
= Tcl_EvalObjEx(interp
, pEval
, 0) ? SQLITE_ERROR
: SQLITE_OK
;
285 Tcl_Obj
*pRes
= Tcl_GetObjResult(interp
);
287 if( Tcl_ListObjGetElements(interp
, pRes
, &nObj
, &aObj
)
289 || Tcl_GetDoubleFromObj(interp
, aObj
[1], &rScore
)
290 || Tcl_GetIndexFromObj(interp
, aObj
[0], azParentWithin
, "value", 0, &eP
)
294 pInfo
->rScore
= rScore
;
295 pInfo
->eParentWithin
= eP
;
299 Tcl_DecrRefCount(pArg
);
300 Tcl_DecrRefCount(pEval
);
304 static void box_query_destroy(void *p
){
305 BoxQueryCtx
*pCtx
= (BoxQueryCtx
*)p
;
306 Tcl_DecrRefCount(pCtx
->pScript
);
310 static int SQLITE_TCLAPI
register_box_query(
314 Tcl_Obj
*CONST objv
[]
316 extern int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
317 extern const char *sqlite3ErrName(int);
322 Tcl_WrongNumArgs(interp
, 1, objv
, "DB SCRIPT");
325 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
327 pCtx
= (BoxQueryCtx
*)ckalloc(sizeof(BoxQueryCtx
));
328 pCtx
->interp
= interp
;
329 pCtx
->pScript
= Tcl_DuplicateObj(objv
[2]);
330 Tcl_IncrRefCount(pCtx
->pScript
);
332 sqlite3_rtree_query_callback(
333 db
, "qbox", box_query
, (void*)pCtx
, box_query_destroy
336 Tcl_ResetResult(interp
);
339 #endif /* SQLITE_ENABLE_RTREE */
342 int Sqlitetestrtreedoc_Init(Tcl_Interp
*interp
){
343 #ifdef SQLITE_ENABLE_RTREE
344 Tcl_CreateObjCommand(interp
, "register_box_geom", register_box_geom
, 0, 0);
345 Tcl_CreateObjCommand(interp
, "register_box_query", register_box_query
, 0, 0);
346 #endif /* SQLITE_ENABLE_RTREE */