Fixes default log output to console for macOS
[sqlcipher.git] / ext / rtree / test_rtreedoc.c
blobcdbcb2e8dc8ec73a3b72106b0b10558f59f2c9ac
1 /*
2 ** 2010 August 28
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
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.
16 #include "sqlite3.h"
17 #if defined(INCLUDE_SQLITE_TCL_H)
18 # include "sqlite_tcl.h"
19 #else
20 # include "tcl.h"
21 #endif
23 /* Solely for the UNUSED_PARAMETER() macro. */
24 #include "sqliteInt.h"
26 #ifdef SQLITE_ENABLE_RTREE
28 typedef struct BoxGeomCtx BoxGeomCtx;
29 struct BoxGeomCtx {
30 Tcl_Interp *interp;
31 Tcl_Obj *pScript;
34 typedef struct BoxQueryCtx BoxQueryCtx;
35 struct BoxQueryCtx {
36 Tcl_Interp *interp;
37 Tcl_Obj *pScript;
40 static void testDelUser(void *pCtx){
41 BoxGeomCtx *p = (BoxGeomCtx*)pCtx;
42 Tcl_EvalObjEx(p->interp, p->pScript, 0);
43 Tcl_DecrRefCount(p->pScript);
44 sqlite3_free(p);
47 static int invokeTclGeomCb(
48 const char *zName,
49 sqlite3_rtree_geometry *p,
50 int nCoord,
51 sqlite3_rtree_dbl *aCoord
53 int rc = SQLITE_OK;
54 if( p->pContext ){
55 char aPtr[64];
56 BoxGeomCtx *pCtx = (BoxGeomCtx*)p->pContext;
57 Tcl_Interp *interp = pCtx->interp;
58 Tcl_Obj *pScript = 0;
59 Tcl_Obj *pParam = 0;
60 Tcl_Obj *pCoord = 0;
61 int ii;
62 Tcl_Obj *pRes;
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);
90 if( rc!=TCL_OK ){
91 rc = SQLITE_ERROR;
92 }else{
93 int nObj = 0;
94 Tcl_Obj **aObj = 0;
96 pRes = Tcl_GetObjResult(interp);
97 if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) ) return TCL_ERROR;
98 if( nObj>0 ){
99 const char *zCmd = Tcl_GetString(aObj[0]);
100 if( 0==sqlite3_stricmp(zCmd, "zero") ){
101 p->aParam[0] = 0.0;
102 p->nParam = 1;
104 else if( 0==sqlite3_stricmp(zCmd, "user") ){
105 if( p->pUser || p->xDelUser ){
106 rc = SQLITE_ERROR;
107 }else{
108 BoxGeomCtx *pBGCtx = sqlite3_malloc(sizeof(BoxGeomCtx));
109 if( pBGCtx==0 ){
110 rc = SQLITE_NOMEM;
111 }else{
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;
127 return rc;
131 # EVIDENCE-OF: R-00693-36727 The legacy xGeom callback is invoked with
132 # four arguments.
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.
145 static int box_geom(
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 */
151 int ii;
153 if( p->nParam!=nCoord ){
154 invokeTclGeomCb("box", p, nCoord, aCoord);
155 return SQLITE_ERROR;
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] ){
161 /* R-28207-40885 */
162 *pRes = 0;
163 return SQLITE_OK;
167 /* R-28207-40885 */
168 *pRes = 1;
170 return SQLITE_OK;
173 static int SQLITE_TCLAPI register_box_geom(
174 void * clientData,
175 Tcl_Interp *interp,
176 int objc,
177 Tcl_Obj *CONST objv[]
179 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
180 extern const char *sqlite3ErrName(int);
181 sqlite3 *db;
182 BoxGeomCtx *pCtx;
183 char aPtr[64];
185 if( objc!=3 ){
186 Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT");
187 return TCL_ERROR;
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));
200 return TCL_OK;
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;
207 Tcl_Obj *pEval;
208 Tcl_Obj *pArg;
209 Tcl_Obj *pTmp = 0;
210 int rc;
211 int ii;
213 pEval = Tcl_DuplicateObj(pCtx->pScript);
214 Tcl_IncrRefCount(pEval);
215 pArg = Tcl_NewObj();
216 Tcl_IncrRefCount(pArg);
218 /* aParam[] */
219 pTmp = Tcl_NewObj();
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);
229 /* aCoord[] */
230 pTmp = Tcl_NewObj();
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);
240 /* anQueue[] */
241 pTmp = Tcl_NewObj();
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);
251 /* iLevel */
252 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("iLevel", -1));
253 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewIntObj(pInfo->iLevel));
255 /* mxLevel */
256 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("mxLevel", -1));
257 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewIntObj(pInfo->mxLevel));
259 /* iRowid */
260 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("iRowid", -1));
261 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewWideIntObj(pInfo->iRowid));
263 /* rParentScore */
264 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("rParentScore", -1));
265 Tcl_ListObjAppendElement(interp, pArg, Tcl_NewDoubleObj(pInfo->rParentScore));
267 /* eParentWithin */
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;
280 if( rc==SQLITE_OK ){
281 double rScore = 0.0;
282 int nObj = 0;
283 int eP = 0;
284 Tcl_Obj **aObj = 0;
285 Tcl_Obj *pRes = Tcl_GetObjResult(interp);
287 if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj)
288 || nObj!=2
289 || Tcl_GetDoubleFromObj(interp, aObj[1], &rScore)
290 || Tcl_GetIndexFromObj(interp, aObj[0], azParentWithin, "value", 0, &eP)
292 rc = SQLITE_ERROR;
293 }else{
294 pInfo->rScore = rScore;
295 pInfo->eParentWithin = eP;
299 Tcl_DecrRefCount(pArg);
300 Tcl_DecrRefCount(pEval);
301 return rc;
304 static void box_query_destroy(void *p){
305 BoxQueryCtx *pCtx = (BoxQueryCtx*)p;
306 Tcl_DecrRefCount(pCtx->pScript);
307 ckfree((char*)pCtx);
310 static int SQLITE_TCLAPI register_box_query(
311 void * clientData,
312 Tcl_Interp *interp,
313 int objc,
314 Tcl_Obj *CONST objv[]
316 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
317 extern const char *sqlite3ErrName(int);
318 sqlite3 *db;
319 BoxQueryCtx *pCtx;
321 if( objc!=3 ){
322 Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT");
323 return TCL_ERROR;
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);
337 return TCL_OK;
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 */
347 return TCL_OK;