2 /* Jim - Sqlite bindings
3 * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * A copy of the license is also included in the source distribution
12 * of Jim, as a TXT file name called LICENSE.
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
26 #include "jimautoconf.h"
28 typedef struct JimSqliteHandle
33 static void JimSqliteDelProc(Jim_Interp
*interp
, void *privData
)
35 JimSqliteHandle
*sh
= privData
;
43 static char *JimSqliteQuoteString(const char *str
, int len
, int *newLenPtr
)
49 for (i
= 0; i
< len
; i
++)
54 d
= buf
= Jim_Alloc(newLen
);
64 static Jim_Obj
*JimSqliteFormatQuery(Jim_Interp
*interp
, Jim_Obj
*fmtObjPtr
,
65 int objc
, Jim_Obj
*const *objv
)
71 fmt
= Jim_GetString(fmtObjPtr
, &fmtLen
);
72 resObjPtr
= Jim_NewStringObj(interp
, "", 0);
77 while (*fmt
!= '%' && fmtLen
) {
81 Jim_AppendString(interp
, resObjPtr
, p
, fmt
- p
);
85 fmtLen
--; /* skip '%' */
88 Jim_FreeNewObj(interp
, resObjPtr
);
89 Jim_SetResultString(interp
, "not enough arguments for all format specifiers", -1);
103 str
= Jim_GetString(objv
[0], &len
);
104 quoted
= JimSqliteQuoteString(str
, len
, &newLen
);
105 Jim_AppendString(interp
, resObjPtr
, quoted
, newLen
);
111 Jim_AppendString(interp
, resObjPtr
, "%", 1);
116 Jim_FreeNewObj(interp
, resObjPtr
);
117 Jim_SetResultFormatted(interp
,
118 "bad field specifier \"%s\", only %%s and %%%% are valid", spec
);
127 /* Calls to [sqlite.open] create commands that are implemented by this
129 static int JimSqliteHandlerCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
131 JimSqliteHandle
*sh
= Jim_CmdPrivData(interp
);
133 static const char * const options
[] = {
134 "close", "query", "lastid", "changes", NULL
137 { OPT_CLOSE
, OPT_QUERY
, OPT_LASTID
, OPT_CHANGES
};
140 Jim_WrongNumArgs(interp
, 1, argv
, "method ?args ...?");
143 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, "Sqlite method", JIM_ERRMSG
) != JIM_OK
)
146 if (option
== OPT_CLOSE
) {
148 Jim_WrongNumArgs(interp
, 2, argv
, "");
151 Jim_DeleteCommand(interp
, Jim_String(argv
[0]));
154 else if (option
== OPT_QUERY
) {
156 Jim_Obj
*objPtr
, *rowsListPtr
;
159 const char *query
, *tail
, **values
, **names
;
163 if (argc
>= 4 && Jim_CompareStringImmediate(interp
, argv
[2], "-null")) {
164 nullstr
= Jim_StrDup(Jim_String(argv
[3]));
169 nullstr
= Jim_StrDup("");
172 Jim_WrongNumArgs(interp
, 2, argv
, "query ?args?");
176 objPtr
= JimSqliteFormatQuery(interp
, argv
[2], argc
- 3, argv
+ 3);
177 if (objPtr
== NULL
) {
181 query
= Jim_String(objPtr
);
182 Jim_IncrRefCount(objPtr
);
183 /* Compile the query into VM code */
184 if (sqlite_compile(sh
->db
, query
, &tail
, &vm
, &errMsg
) != SQLITE_OK
) {
185 Jim_DecrRefCount(interp
, objPtr
);
186 Jim_SetResultString(interp
, errMsg
, -1);
187 sqlite_freemem(errMsg
);
191 Jim_DecrRefCount(interp
, objPtr
); /* query no longer needed. */
192 /* Build a list of rows (that are lists in turn) */
193 rowsListPtr
= Jim_NewListObj(interp
, NULL
, 0);
194 Jim_IncrRefCount(rowsListPtr
);
196 while (sqlite_step(vm
, &columns
, &values
, &names
) == SQLITE_ROW
) {
199 objPtr
= Jim_NewListObj(interp
, NULL
, 0);
200 for (i
= 0; i
< columns
; i
++) {
201 Jim_ListAppendElement(interp
, objPtr
, Jim_NewStringObj(interp
, names
[i
], -1));
202 Jim_ListAppendElement(interp
, objPtr
,
203 Jim_NewStringObj(interp
, values
[i
] != NULL
? values
[i
] : nullstr
, -1));
205 Jim_ListAppendElement(interp
, rowsListPtr
, objPtr
);
210 if (sqlite_finalize(vm
, &errMsg
) != SQLITE_OK
) {
211 Jim_DecrRefCount(interp
, rowsListPtr
);
212 Jim_SetResultString(interp
, errMsg
, -1);
213 sqlite_freemem(errMsg
);
216 Jim_SetResult(interp
, rowsListPtr
);
217 Jim_DecrRefCount(interp
, rowsListPtr
);
219 else if (option
== OPT_LASTID
) {
221 Jim_WrongNumArgs(interp
, 2, argv
, "");
224 Jim_SetResult(interp
, Jim_NewIntObj(interp
, sqlite_last_insert_rowid(sh
->db
)));
227 else if (option
== OPT_CHANGES
) {
229 Jim_WrongNumArgs(interp
, 2, argv
, "");
232 Jim_SetResult(interp
, Jim_NewIntObj(interp
, sqlite_changes(sh
->db
)));
238 static int JimSqliteOpenCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
242 char buf
[60], *errMsg
;
245 Jim_WrongNumArgs(interp
, 1, argv
, "dbname");
248 db
= sqlite_open(Jim_String(argv
[1]), 0, &errMsg
);
250 Jim_SetResultString(interp
, errMsg
, -1);
251 sqlite_freemem(errMsg
);
254 /* Create the file command */
255 sh
= Jim_Alloc(sizeof(*sh
));
257 snprintf(buf
, sizeof(buf
), "sqlite.handle%ld", Jim_GetId(interp
));
258 Jim_CreateCommand(interp
, buf
, JimSqliteHandlerCommand
, sh
, JimSqliteDelProc
);
259 Jim_SetResultString(interp
, buf
, -1);
263 int Jim_sqliteInit(Jim_Interp
*interp
)
265 if (Jim_PackageProvide(interp
, "sqlite", "1.0", JIM_ERRMSG
))
268 Jim_CreateCommand(interp
, "sqlite.open", JimSqliteOpenCommand
, NULL
, NULL
);