| 3251 |
mrmanese |
1 |
#include <stdio.h>
|
|
|
2 |
#include <string.h>
|
|
|
3 |
|
| 3252 |
mrmanese |
4 |
#define __SQLITE_WORKSPACE__
|
|
|
5 |
#include "sqlite_dataframe.h"
|
| 3251 |
mrmanese |
6 |
|
| 3307 |
mrmanese |
7 |
/* global variables */
|
| 3252 |
mrmanese |
8 |
sqlite3 *g_workspace = NULL;
|
|
|
9 |
char *g_sql_buf[NBUFS];
|
|
|
10 |
int g_sql_buf_sz[NBUFS];
|
|
|
11 |
|
| 3307 |
mrmanese |
12 |
/****************************************************************************
|
|
|
13 |
* UTILITY FUNCTIONS
|
|
|
14 |
****************************************************************************/
|
|
|
15 |
|
|
|
16 |
/* test if a file is a sqlite database file */
|
| 4798 |
mrmanese |
17 |
sqlite3* _is_sqlitedb(const char *filename) {
|
| 3251 |
mrmanese |
18 |
sqlite3 *db;
|
|
|
19 |
int res;
|
|
|
20 |
res = sqlite3_open(filename, &db);
|
|
|
21 |
if (res != SQLITE_OK) { goto is_sqlitedb_FAIL; }
|
|
|
22 |
|
| 3252 |
mrmanese |
23 |
sqlite3_stmt *stmt; char *sql = "select * from sqlite_master";
|
| 3255 |
mrmanese |
24 |
res = sqlite3_prepare(db, sql, -1, &stmt, 0);
|
| 3251 |
mrmanese |
25 |
if (stmt != NULL) sqlite3_finalize(stmt);
|
|
|
26 |
/*char **result_set;
|
|
|
27 |
char nrow, ncol;
|
|
|
28 |
res = sqlite3_get_table(db, "select * from sqlite_master limit 0",
|
|
|
29 |
&result_set, &nrow, &ncol, NULL);
|
|
|
30 |
sqlite3_free_table(result_set);*/
|
|
|
31 |
if (res != SQLITE_OK) goto is_sqlitedb_FAIL;
|
|
|
32 |
|
|
|
33 |
return db;
|
|
|
34 |
|
|
|
35 |
is_sqlitedb_FAIL:
|
| 3252 |
mrmanese |
36 |
sqlite3_close(db);
|
| 3251 |
mrmanese |
37 |
return NULL;
|
|
|
38 |
}
|
|
|
39 |
|
| 3307 |
mrmanese |
40 |
/* test if a file is a SQLiteDF workspace */
|
| 3251 |
mrmanese |
41 |
sqlite3* _is_workspace(char *filename) {
|
|
|
42 |
sqlite3* db = _is_sqlitedb(filename);
|
|
|
43 |
|
|
|
44 |
if (db != NULL) {
|
|
|
45 |
sqlite3_stmt *stmt;
|
|
|
46 |
char *sql = "select * from workspace";
|
| 3255 |
mrmanese |
47 |
int res = sqlite3_prepare(db, sql, -1, &stmt, 0), ncols;
|
| 3251 |
mrmanese |
48 |
if ((res != SQLITE_OK) || /* no workspace table */
|
| 3255 |
mrmanese |
49 |
((ncols = sqlite3_column_count(stmt)) != WORKSPACE_COLUMNS) ||
|
| 3251 |
mrmanese |
50 |
/* below also checks the ordering of the columns */
|
| 3255 |
mrmanese |
51 |
(strcmp(sqlite3_column_name(stmt, 0), "rel_filename") != 0) ||
|
| 3252 |
mrmanese |
52 |
(strcmp(sqlite3_column_decltype(stmt, 0), "text") != 0) ||
|
| 3255 |
mrmanese |
53 |
(strcmp(sqlite3_column_name(stmt, 1), "full_filename") != 0) ||
|
|
|
54 |
(strcmp(sqlite3_column_decltype(stmt, 1), "text") != 0) ||
|
|
|
55 |
(strcmp(sqlite3_column_name(stmt, 2), "internal_name") != 0) ||
|
| 3308 |
mrmanese |
56 |
(strcmp(sqlite3_column_decltype(stmt, 2), "text") != 0) ||
|
|
|
57 |
(strcmp(sqlite3_column_name(stmt, 3), "loaded") != 0) ||
|
|
|
58 |
(strcmp(sqlite3_column_decltype(stmt, 3), "bit") != 0) ||
|
|
|
59 |
(strcmp(sqlite3_column_name(stmt, 4), "uses") != 0) ||
|
| 3419 |
mrmanese |
60 |
(strcmp(sqlite3_column_decltype(stmt, 4), "int") != 0) ||
|
|
|
61 |
(strcmp(sqlite3_column_name(stmt, 5), "used") != 0) ||
|
|
|
62 |
(strcmp(sqlite3_column_decltype(stmt, 5), "bit") != 0)) {
|
| 3251 |
mrmanese |
63 |
sqlite3_finalize(stmt); sqlite3_close(db); db = NULL;
|
|
|
64 |
} else {
|
|
|
65 |
sqlite3_finalize(stmt);
|
|
|
66 |
}
|
|
|
67 |
}
|
|
|
68 |
|
|
|
69 |
return db;
|
|
|
70 |
}
|
|
|
71 |
|
| 3307 |
mrmanese |
72 |
/* test if a file is a sqlite.data.frame. returns the internal name of the
|
|
|
73 |
* sdf if file is an sdf or NULL otherwise */
|
| 4798 |
mrmanese |
74 |
const char * _is_sdf2(const char *filename) {
|
| 3251 |
mrmanese |
75 |
sqlite3* db = _is_sqlitedb(filename);
|
| 4798 |
mrmanese |
76 |
const char *ret = (db == NULL) ? NULL : filename;
|
| 3251 |
mrmanese |
77 |
|
| 3252 |
mrmanese |
78 |
if (ret) {
|
| 3251 |
mrmanese |
79 |
sqlite3_stmt *stmt;
|
| 3307 |
mrmanese |
80 |
char *sql = "select * from sdf_attributes where attr='name'";
|
|
|
81 |
int res, ncols;
|
|
|
82 |
res = sqlite3_prepare(db, sql, -1, &stmt, NULL);
|
|
|
83 |
ret = (((res == SQLITE_OK) && /* no attribute table */
|
| 3252 |
mrmanese |
84 |
((ncols = sqlite3_column_count(stmt)) == 2) &&
|
|
|
85 |
(strcmp(sqlite3_column_name(stmt, 0), "attr") == 0) &&
|
|
|
86 |
(strcmp(sqlite3_column_decltype(stmt, 0), "text") == 0) &&
|
|
|
87 |
(strcmp(sqlite3_column_name(stmt, 1), "value") == 0) &&
|
| 3307 |
mrmanese |
88 |
(strcmp(sqlite3_column_decltype(stmt, 1), "text") == 0))) ? ret : NULL ;
|
| 3251 |
mrmanese |
89 |
|
| 3307 |
mrmanese |
90 |
if (ret == NULL) goto _is_sdf_cleanup;
|
|
|
91 |
|
| 3471 |
mrmanese |
92 |
/* get internal name. we are assuming here that the 1st row of the attributes
|
|
|
93 |
* table always contains the column name */
|
| 3307 |
mrmanese |
94 |
res = sqlite3_step(stmt);
|
|
|
95 |
ret = (res == SQLITE_ROW) ? ret : NULL;
|
|
|
96 |
if (ret == NULL) goto _is_sdf_cleanup;
|
|
|
97 |
|
|
|
98 |
/* copy to buf2, because when we finalize stmt, we won't be sure
|
|
|
99 |
* if sqlite3_column_text()'s ret value will still be there */
|
|
|
100 |
strcpy(g_sql_buf[2], (char *)sqlite3_column_text(stmt, 1));
|
|
|
101 |
ret = g_sql_buf[2];
|
|
|
102 |
sqlite3_finalize(stmt);
|
| 3252 |
mrmanese |
103 |
|
|
|
104 |
sql = "select * from sdf_data";
|
| 3255 |
mrmanese |
105 |
res = sqlite3_prepare(db, sql, -1, &stmt, NULL);
|
| 3307 |
mrmanese |
106 |
ret = (res == SQLITE_OK) ? ret : NULL; /* if not, missing data table */
|
| 3252 |
mrmanese |
107 |
|
|
|
108 |
_is_sdf_cleanup:
|
| 3251 |
mrmanese |
109 |
sqlite3_finalize(stmt);
|
| 3252 |
mrmanese |
110 |
sqlite3_close(db);
|
| 3251 |
mrmanese |
111 |
}
|
|
|
112 |
|
| 3252 |
mrmanese |
113 |
return ret;
|
| 3251 |
mrmanese |
114 |
}
|
|
|
115 |
|
| 3307 |
mrmanese |
116 |
/* remove an sdf from the workspace */
|
| 3324 |
mrmanese |
117 |
void _delete_sdf2(const char *iname) {
|
| 3252 |
mrmanese |
118 |
sprintf(g_sql_buf[2], "delete from workspace where internal_name='%s';", iname);
|
|
|
119 |
_sqlite_exec(g_sql_buf[2]);
|
| 3251 |
mrmanese |
120 |
}
|
|
|
121 |
|
| 3307 |
mrmanese |
122 |
/* add a sdf to the workspace */
|
| 4798 |
mrmanese |
123 |
int _add_sdf1(const char *filename, const char *internal_name) {
|
| 3308 |
mrmanese |
124 |
sprintf(g_sql_buf[1], "insert into workspace(rel_filename, full_filename, "
|
| 3419 |
mrmanese |
125 |
"internal_name, loaded, uses, used) values('%s', '%s', '%s', 0, 0, 0)",
|
| 3255 |
mrmanese |
126 |
filename, _get_full_pathname2(filename), internal_name);
|
| 3419 |
mrmanese |
127 |
|
| 3255 |
mrmanese |
128 |
return _sqlite_exec(g_sql_buf[1]);
|
|
|
129 |
}
|
| 3251 |
mrmanese |
130 |
|
| 3307 |
mrmanese |
131 |
|
| 4798 |
mrmanese |
132 |
static char* _get_sdf_detail2(const char *iname, int what) {
|
| 3307 |
mrmanese |
133 |
sqlite3_stmt *stmt;
|
|
|
134 |
char * ret; int res;
|
|
|
135 |
|
|
|
136 |
sprintf(g_sql_buf[2], "select full_filename from workspace where "
|
|
|
137 |
"internal_name='%s'", iname);
|
|
|
138 |
sqlite3_prepare(g_workspace, g_sql_buf[2], -1, &stmt, NULL);
|
|
|
139 |
res = sqlite3_step(stmt);
|
|
|
140 |
sqlite3_finalize(stmt);
|
|
|
141 |
|
|
|
142 |
if (res == SQLITE_DONE) {
|
|
|
143 |
ret = NULL;
|
|
|
144 |
} else {
|
|
|
145 |
ret = g_sql_buf[2];
|
|
|
146 |
switch (what) {
|
|
|
147 |
case SDF_DETAIL_EXISTS:
|
|
|
148 |
break; /* doesn't matter */
|
|
|
149 |
case SDF_DETAIL_FULLFILENAME:
|
|
|
150 |
strcpy(g_sql_buf[2], (char *)sqlite3_column_text(stmt, 0));
|
|
|
151 |
break;
|
|
|
152 |
}
|
|
|
153 |
}
|
|
|
154 |
|
|
|
155 |
return ret;
|
|
|
156 |
}
|
|
|
157 |
|
|
|
158 |
/* returns TRUE if sdf exists in the workspace */
|
| 4798 |
mrmanese |
159 |
int _sdf_exists2(const char *iname) {
|
| 3307 |
mrmanese |
160 |
return _get_sdf_detail2(iname, SDF_DETAIL_EXISTS) != NULL;
|
|
|
161 |
}
|
|
|
162 |
|
|
|
163 |
/****************************************************************************
|
|
|
164 |
* WORKSPACE FUNCTIONS
|
|
|
165 |
****************************************************************************/
|
|
|
166 |
|
| 3251 |
mrmanese |
167 |
SEXP sdf_init_workspace() {
|
| 3252 |
mrmanese |
168 |
int file_idx = 0, i;
|
| 3251 |
mrmanese |
169 |
char *basename = "workspace", *filename;
|
|
|
170 |
SEXP ret;
|
|
|
171 |
|
| 3252 |
mrmanese |
172 |
/* initialize sql_buf */
|
|
|
173 |
for (i = 0; i < NBUFS; i++) {
|
|
|
174 |
if (g_sql_buf[i] == NULL) {
|
|
|
175 |
g_sql_buf_sz[i] = 1024;
|
|
|
176 |
g_sql_buf[i] = Calloc(g_sql_buf_sz[i], char);
|
|
|
177 |
}
|
|
|
178 |
}
|
|
|
179 |
|
| 3446 |
mrmanese |
180 |
/* create symbols used for object attributes */
|
|
|
181 |
SDF_RowNamesSymbol = install("sdf.row.names");
|
| 3456 |
mrmanese |
182 |
SDF_VectorTypeSymbol = install("sdf.vector.type");
|
| 3446 |
mrmanese |
183 |
SDF_DimSymbol = install("sdf.dim");
|
|
|
184 |
SDF_DimNamesSymbol = install("sdf.dimnames");
|
|
|
185 |
|
| 3252 |
mrmanese |
186 |
/*
|
|
|
187 |
* check for workspace.db, workspace1.db, ..., workspace9999.db if they
|
| 3251 |
mrmanese |
188 |
* are valid workspace file. if one is found, use that as the workspace.
|
|
|
189 |
*/
|
| 3684 |
mrmanese |
190 |
filename = R_alloc(28, sizeof(char)); /* .SQLiteDF/workspace10000.db\0 */
|
|
|
191 |
sprintf(filename, ".SQLiteDF/%s.db", basename);
|
| 3252 |
mrmanese |
192 |
while(_file_exists(filename) && file_idx < 10000) {
|
|
|
193 |
if ((g_workspace = _is_workspace(filename)) != NULL) break;
|
| 3471 |
mrmanese |
194 |
warning("%s is not a SQLiteDF workspace\n", filename);
|
| 3684 |
mrmanese |
195 |
sprintf(filename, ".SQLiteDF/%s%d.db", basename, ++file_idx);
|
| 3251 |
mrmanese |
196 |
}
|
|
|
197 |
|
| 3252 |
mrmanese |
198 |
if ((g_workspace == NULL) && (file_idx < 10000)) {
|
| 3251 |
mrmanese |
199 |
/* no workspace found but there are still "available" file name */
|
|
|
200 |
/* if (file_idx) warn("workspace will be stored at #{filename}") */
|
| 3252 |
mrmanese |
201 |
sqlite3_open(filename, &g_workspace);
|
| 3308 |
mrmanese |
202 |
_sqlite_exec("create table workspace(rel_filename text, full_filename text,"
|
| 3471 |
mrmanese |
203 |
"internal_name text unique, loaded bit, uses int, used bit)");
|
| 3446 |
mrmanese |
204 |
ret = ScalarLogical(TRUE);
|
| 3252 |
mrmanese |
205 |
} else if (g_workspace != NULL) {
|
| 3251 |
mrmanese |
206 |
/* a valid workspace has been found, load each of the tables */
|
|
|
207 |
int res, nrows, ncols;
|
|
|
208 |
char **result_set, *fname, *iname;
|
|
|
209 |
|
| 3308 |
mrmanese |
210 |
/* since only 30 can be loaded, sort sdf's by # of uses the last time */
|
| 3324 |
mrmanese |
211 |
res = sqlite3_get_table(g_workspace, "select rel_filename, internal_name"
|
|
|
212 |
" from workspace order by uses desc",
|
| 3251 |
mrmanese |
213 |
&result_set, &nrows, &ncols, NULL);
|
| 3308 |
mrmanese |
214 |
|
|
|
215 |
/* reset fields uses and loaded to 0 and false */
|
| 3419 |
mrmanese |
216 |
res = _sqlite_exec("update workspace set uses=0, loaded=0, used=0");
|
| 3308 |
mrmanese |
217 |
_sqlite_error(res);
|
| 3251 |
mrmanese |
218 |
|
| 3324 |
mrmanese |
219 |
if (res == SQLITE_OK && nrows >= 1 && ncols == 2) {
|
| 3308 |
mrmanese |
220 |
int maxrows; /* actual # of sdfs to be attached */
|
|
|
221 |
maxrows = (nrows > 30) ? 30 : nrows;
|
|
|
222 |
for (i = 1; i <= maxrows && i < nrows; i++) {
|
| 3255 |
mrmanese |
223 |
/* we will use rel_filename in opening the file, so that
|
|
|
224 |
* if the user is "sensible", files will be dir agnostic */
|
| 3324 |
mrmanese |
225 |
fname = result_set[i*ncols]; iname = result_set[i*ncols+1];
|
| 3251 |
mrmanese |
226 |
|
| 3419 |
mrmanese |
227 |
if (!USE_SDF1(iname, TRUE, FALSE)) maxrows++;
|
| 3251 |
mrmanese |
228 |
|
| 3255 |
mrmanese |
229 |
/* update full_filename */
|
| 3419 |
mrmanese |
230 |
sprintf(g_sql_buf[0], "update workspace set full_filename='%s' "
|
| 3308 |
mrmanese |
231 |
"where iname='%s'", _get_full_pathname2(fname), iname);
|
| 3255 |
mrmanese |
232 |
_sqlite_exec(g_sql_buf[0]);
|
| 3251 |
mrmanese |
233 |
}
|
|
|
234 |
}
|
|
|
235 |
sqlite3_free_table(result_set);
|
|
|
236 |
|
| 3509 |
mrmanese |
237 |
/* notify if a previous workspace is reloaded */
|
| 3684 |
mrmanese |
238 |
Rprintf("[Previous SQLiteDF workspace restored (%s)]\n", filename);
|
| 3509 |
mrmanese |
239 |
|
| 3446 |
mrmanese |
240 |
ret = ScalarLogical(TRUE);
|
| 3251 |
mrmanese |
241 |
} else { /* can't find nor create workspace */
|
| 3446 |
mrmanese |
242 |
ret = ScalarLogical(FALSE);
|
| 3251 |
mrmanese |
243 |
}
|
|
|
244 |
|
| 3307 |
mrmanese |
245 |
/* register sqlite math functions */
|
|
|
246 |
__register_vector_math();
|
| 3251 |
mrmanese |
247 |
return ret;
|
|
|
248 |
}
|
|
|
249 |
|
| 3419 |
mrmanese |
250 |
int USE_SDF1(const char *iname, int exists, int protect) {
|
| 3308 |
mrmanese |
251 |
sqlite3_stmt *stmt;
|
|
|
252 |
int loaded, res;
|
| 3471 |
mrmanese |
253 |
char *iname_final = (char *)iname;
|
| 3251 |
mrmanese |
254 |
|
| 3308 |
mrmanese |
255 |
/* determine if iname is loaded */
|
| 3358 |
mrmanese |
256 |
sprintf(g_sql_buf[2], "select loaded, rel_filename from workspace where internal_name='%s'", iname);
|
|
|
257 |
sqlite3_prepare(g_workspace, g_sql_buf[2], -1, &stmt, NULL);
|
| 3308 |
mrmanese |
258 |
res = sqlite3_step(stmt);
|
| 3324 |
mrmanese |
259 |
if (exists && res != SQLITE_ROW) {
|
| 3684 |
mrmanese |
260 |
sqlite3_finalize(stmt);
|
| 3471 |
mrmanese |
261 |
error("No SDF with name '%s' found in the workspace.\n", iname);
|
| 3308 |
mrmanese |
262 |
}
|
| 3419 |
mrmanese |
263 |
loaded = (res == SQLITE_ROW) ? sqlite3_column_int(stmt, 0) : 0;
|
| 3358 |
mrmanese |
264 |
strcpy(g_sql_buf[1], (char*)sqlite3_column_text(stmt, 1)); /* ref filename */
|
| 3308 |
mrmanese |
265 |
sqlite3_finalize(stmt);
|
|
|
266 |
|
|
|
267 |
if (!loaded) {
|
| 3358 |
mrmanese |
268 |
char *fname = g_sql_buf[1];
|
| 3324 |
mrmanese |
269 |
|
| 3358 |
mrmanese |
270 |
/* test first if we will be loading valid sdf */
|
| 3324 |
mrmanese |
271 |
if (exists && !_file_exists(fname)) {
|
|
|
272 |
_delete_sdf2(iname);
|
| 3471 |
mrmanese |
273 |
warning("SDF %s does not exist.\n", iname);
|
| 3324 |
mrmanese |
274 |
return 0;
|
|
|
275 |
}
|
|
|
276 |
|
|
|
277 |
if (exists && _is_sdf2(fname) == NULL) {
|
|
|
278 |
_delete_sdf2(iname);
|
| 3471 |
mrmanese |
279 |
warning("%s is not a valid SDF.\n", fname);
|
| 3324 |
mrmanese |
280 |
return 0;
|
|
|
281 |
}
|
|
|
282 |
|
| 3471 |
mrmanese |
283 |
/* g_sql_buf[2] contains the internal name as stored in the sdf
|
|
|
284 |
* attribute. sync workspace record to that if needed */
|
|
|
285 |
if (exists && strcmp(iname, g_sql_buf[2]) != 0) {
|
|
|
286 |
if (!_is_r_sym(g_sql_buf[2])) {
|
| 3684 |
mrmanese |
287 |
warning("name \"%s\" stored in SDF is not valid. Ignoring that name...", g_sql_buf[2]);
|
| 3471 |
mrmanese |
288 |
goto __out_of_syncname;
|
|
|
289 |
}
|
|
|
290 |
iname_final = R_alloc(strlen(g_sql_buf[2]) + 1, sizeof(g_sql_buf[2]));
|
|
|
291 |
strcpy(iname_final, g_sql_buf[2]);
|
|
|
292 |
|
|
|
293 |
sprintf(g_sql_buf[2], "update workspace set internal_name='%s' where "
|
|
|
294 |
"internal_name='%s'", iname_final, iname);
|
|
|
295 |
_sqlite_error(_sqlite_exec(g_sql_buf[2]));
|
|
|
296 |
|
|
|
297 |
}
|
|
|
298 |
__out_of_syncname:
|
|
|
299 |
|
| 3397 |
mrmanese |
300 |
/* unload sdf's if we run to the MAX_ATTACHED limit */
|
|
|
301 |
_prepare_attach2();
|
| 3308 |
mrmanese |
302 |
|
|
|
303 |
/* set loaded to true */
|
| 3471 |
mrmanese |
304 |
sprintf(g_sql_buf[2], "update workspace set loaded=1 where internal_name='%s'", iname_final);
|
| 3358 |
mrmanese |
305 |
res = _sqlite_exec(g_sql_buf[2]);
|
| 3324 |
mrmanese |
306 |
_sqlite_error(res);
|
| 3308 |
mrmanese |
307 |
|
|
|
308 |
/* load, using relative path */
|
| 3471 |
mrmanese |
309 |
sprintf(g_sql_buf[2], "attach '%s' as [%s]", fname, iname_final);
|
| 3358 |
mrmanese |
310 |
res = _sqlite_exec(g_sql_buf[2]);
|
| 3308 |
mrmanese |
311 |
if (_sqlite_error(res)) return 0;
|
|
|
312 |
}
|
|
|
313 |
|
| 3419 |
mrmanese |
314 |
/* upgrade its uses count, and protect if necessary */
|
|
|
315 |
if (protect) protect = 1;
|
|
|
316 |
sprintf(g_sql_buf[2], "update workspace set uses=uses+1, used=%d"
|
| 3471 |
mrmanese |
317 |
" where internal_name='%s'", protect, iname_final);
|
| 3358 |
mrmanese |
318 |
_sqlite_exec(g_sql_buf[2]);
|
| 3308 |
mrmanese |
319 |
return 1;
|
|
|
320 |
}
|
|
|
321 |
|
| 3419 |
mrmanese |
322 |
int UNUSE_SDF2(const char *iname) {
|
|
|
323 |
sprintf(g_sql_buf[2], "update workspace set used=0 where internal_name='%s'", iname);
|
|
|
324 |
_sqlite_exec(g_sql_buf[2]);
|
|
|
325 |
return 1;
|
|
|
326 |
}
|
|
|
327 |
|
| 3308 |
mrmanese |
328 |
|
| 3251 |
mrmanese |
329 |
|
| 3252 |
mrmanese |
330 |
SEXP sdf_finalize_workspace() {
|
|
|
331 |
SEXP ret;
|
| 3308 |
mrmanese |
332 |
int i;
|
| 3446 |
mrmanese |
333 |
ret = ScalarLogical(sqlite3_close(g_workspace) == SQLITE_OK);
|
| 3308 |
mrmanese |
334 |
for (i = 0; i < NBUFS; i++) Free(g_sql_buf[i]);
|
| 3252 |
mrmanese |
335 |
return ret;
|
|
|
336 |
}
|
| 3251 |
mrmanese |
337 |
|
|
|
338 |
|
| 3252 |
mrmanese |
339 |
SEXP sdf_list_sdfs(SEXP pattern) {
|
|
|
340 |
SEXP ret;
|
|
|
341 |
char **result;
|
|
|
342 |
int nrow, ncol, res, i;
|
|
|
343 |
|
|
|
344 |
if (TYPEOF(pattern) != STRSXP) {
|
| 3308 |
mrmanese |
345 |
res = sqlite3_get_table(g_workspace, "select internal_name from workspace "
|
|
|
346 |
"order by loaded desc, uses desc", &result, &nrow, &ncol, NULL);
|
| 3252 |
mrmanese |
347 |
} else {
|
|
|
348 |
/* since internal_names must be a valid r symbol,
|
|
|
349 |
did not check for "'" */
|
|
|
350 |
sprintf(g_sql_buf[0], "select internal_name from workspace where "
|
| 3282 |
mrmanese |
351 |
"internal_name like '%s%%'", CHAR(STRING_ELT(pattern, 0)));
|
| 3252 |
mrmanese |
352 |
res = sqlite3_get_table(g_workspace, g_sql_buf[0], &result, &nrow,
|
|
|
353 |
&ncol, NULL);
|
|
|
354 |
}
|
|
|
355 |
|
|
|
356 |
if (_sqlite_error(res)) return R_NilValue;
|
|
|
357 |
PROTECT(ret = NEW_CHARACTER(nrow));
|
|
|
358 |
|
|
|
359 |
for (i = 0; i < nrow; i++) SET_STRING_ELT(ret, i, mkChar(result[i+1]));
|
|
|
360 |
|
|
|
361 |
sqlite3_free_table(result);
|
|
|
362 |
UNPROTECT(1);
|
|
|
363 |
return ret;
|
|
|
364 |
}
|
|
|
365 |
|
|
|
366 |
SEXP sdf_get_sdf(SEXP name) {
|
| 4798 |
mrmanese |
367 |
const char *iname;
|
| 3446 |
mrmanese |
368 |
SEXP ret;
|
|
|
369 |
|
| 3252 |
mrmanese |
370 |
if (TYPEOF(name) != STRSXP) {
|
| 3684 |
mrmanese |
371 |
error("Argument must be a string containing the SDF name.");
|
| 3252 |
mrmanese |
372 |
}
|
| 3446 |
mrmanese |
373 |
iname = CHAR(STRING_ELT(name, 0));
|
| 3252 |
mrmanese |
374 |
|
| 3419 |
mrmanese |
375 |
if (!USE_SDF1(iname, TRUE, FALSE)) return R_NilValue;
|
| 3252 |
mrmanese |
376 |
|
| 3308 |
mrmanese |
377 |
ret = _create_sdf_sexp(iname);
|
| 3252 |
mrmanese |
378 |
return ret;
|
|
|
379 |
}
|
| 3255 |
mrmanese |
380 |
|
|
|
381 |
SEXP sdf_attach_sdf(SEXP filename, SEXP internal_name) {
|
| 3307 |
mrmanese |
382 |
/* when studying this, please be mindful of the global buffers used.
|
|
|
383 |
* you have been warned */
|
| 4798 |
mrmanese |
384 |
const char *fname=NULL, *iname, *iname_orig=NULL;
|
| 3700 |
mrmanese |
385 |
int fnamelen=0, res;
|
| 3255 |
mrmanese |
386 |
sqlite3_stmt *stmt;
|
|
|
387 |
|
|
|
388 |
if (IS_CHARACTER(filename)) {
|
|
|
389 |
fname = CHAR_ELT(filename, 0);
|
|
|
390 |
fnamelen = strlen(fname);
|
|
|
391 |
} else {
|
| 3684 |
mrmanese |
392 |
error("filename argument must be a string.");
|
| 3255 |
mrmanese |
393 |
}
|
|
|
394 |
|
|
|
395 |
if (strcmp(fname+(fnamelen-3),".db") != 0) {
|
| 3684 |
mrmanese |
396 |
error("will not attach because extension is not .db");
|
| 3255 |
mrmanese |
397 |
}
|
|
|
398 |
|
| 3307 |
mrmanese |
399 |
/* check if it is a valid sdf file */
|
|
|
400 |
if (_is_sdf2(fname) == NULL) {
|
| 3684 |
mrmanese |
401 |
error("%s is not a valid SDF.", fname);
|
| 3307 |
mrmanese |
402 |
} else {
|
|
|
403 |
/* _is_sdf2 puts the orig iname in buf2. transfer data to buf0 since
|
|
|
404 |
* functions called below will use buf2 */
|
|
|
405 |
strcpy(g_sql_buf[0], g_sql_buf[2]);
|
|
|
406 |
iname_orig = g_sql_buf[0];
|
|
|
407 |
}
|
|
|
408 |
|
|
|
409 |
/* check if file to be attached exists in the workspace already */
|
| 3255 |
mrmanese |
410 |
_get_full_pathname2(fname);
|
|
|
411 |
res = sqlite3_prepare(g_workspace, "select internal_name from workspace where full_filename=?",
|
|
|
412 |
-1, &stmt, NULL);
|
| 3307 |
mrmanese |
413 |
sqlite3_bind_text(stmt, 1, g_sql_buf[2], -1, SQLITE_STATIC);
|
| 3255 |
mrmanese |
414 |
res = sqlite3_step(stmt);
|
|
|
415 |
if (res == SQLITE_ROW) {
|
| 3684 |
mrmanese |
416 |
warning("this sdf is already attached as '%s'\n",
|
| 3255 |
mrmanese |
417 |
sqlite3_column_text(stmt, 0));
|
|
|
418 |
sqlite3_finalize(stmt);
|
|
|
419 |
return R_NilValue;
|
|
|
420 |
} else sqlite3_finalize(stmt);
|
|
|
421 |
|
|
|
422 |
|
|
|
423 |
/* internal_name checking and processing. */
|
|
|
424 |
if (IS_CHARACTER(internal_name)) {
|
| 3307 |
mrmanese |
425 |
/* if name is specified, rename the sdf. original internal name is the
|
|
|
426 |
* one stored at sdf_attribute */
|
| 3255 |
mrmanese |
427 |
iname = CHAR_ELT(internal_name, 0);
|
|
|
428 |
if (!_is_r_sym(iname)) {
|
| 3684 |
mrmanese |
429 |
error("%s is not a valid R symbol.", iname);
|
| 3255 |
mrmanese |
430 |
}
|
|
|
431 |
} else {
|
| 3307 |
mrmanese |
432 |
/* if no name is specified, use original internal name */
|
|
|
433 |
iname = (char *)iname_orig; /* g_sql_buf[0]! */
|
|
|
434 |
}
|
| 3255 |
mrmanese |
435 |
|
| 3307 |
mrmanese |
436 |
/* check if internal name is already used in the workspace */
|
|
|
437 |
res = sqlite3_prepare(g_workspace, "select full_filename from workspace "
|
|
|
438 |
" where internal_name=?", -1, &stmt, NULL);
|
|
|
439 |
sqlite3_bind_text(stmt, 1, iname, -1, SQLITE_STATIC);
|
|
|
440 |
res = sqlite3_step(stmt);
|
|
|
441 |
if (res == SQLITE_ROW) {
|
| 3684 |
mrmanese |
442 |
strcpy(g_sql_buf[0], (char *)sqlite3_column_text(stmt,1));
|
| 3255 |
mrmanese |
443 |
sqlite3_finalize(stmt);
|
| 3684 |
mrmanese |
444 |
error("the sdf internal name '%s' is already used by file %s.",
|
|
|
445 |
iname, g_sql_buf[0]);
|
| 3307 |
mrmanese |
446 |
}
|
|
|
447 |
sqlite3_finalize(stmt);
|
|
|
448 |
|
| 3308 |
mrmanese |
449 |
/* add it to workspace */
|
|
|
450 |
res = _add_sdf1(fname, iname);
|
| 3255 |
mrmanese |
451 |
if (_sqlite_error(res)) return R_NilValue;
|
|
|
452 |
|
| 3358 |
mrmanese |
453 |
/* attach using USE_SDF1, detach other SDF if necessary */
|
| 3419 |
mrmanese |
454 |
USE_SDF1(iname, TRUE, FALSE);
|
| 3308 |
mrmanese |
455 |
|
| 3307 |
mrmanese |
456 |
/* if internal name found in newly-attached-SDF is the same as the
|
|
|
457 |
* name wanted by the user, do nothing. otherwise, update sdf_attribute
|
|
|
458 |
* on attached-SDF. this is like attachSdf then renameSdf */
|
|
|
459 |
if (iname != iname_orig && strcmp(iname, iname_orig) != 0) {
|
|
|
460 |
sprintf(g_sql_buf[1], "update [%s].sdf_attributes set value=? where attr='name'",
|
|
|
461 |
iname);
|
|
|
462 |
res = sqlite3_prepare(g_workspace, g_sql_buf[0], -1, &stmt, NULL);
|
|
|
463 |
if (_sqlite_error(res)) {
|
|
|
464 |
sqlite3_finalize(stmt);
|
|
|
465 |
sprintf(g_sql_buf[1], "detach [%s]", iname);
|
|
|
466 |
_sqlite_exec(g_sql_buf[1]);
|
|
|
467 |
return R_NilValue;
|
|
|
468 |
}
|
|
|
469 |
res = sqlite3_bind_text(stmt, 1, iname, -1, SQLITE_STATIC);
|
|
|
470 |
res = sqlite3_step(stmt);
|
|
|
471 |
sqlite3_finalize(stmt);
|
|
|
472 |
}
|
|
|
473 |
|
| 3255 |
mrmanese |
474 |
return _create_sdf_sexp(iname);
|
|
|
475 |
}
|
|
|
476 |
|
| 3308 |
mrmanese |
477 |
/* not necessary anymore, since stuffs will eventually be detached
|
|
|
478 |
* if we keep on adding new sdfs */
|
| 3255 |
mrmanese |
479 |
SEXP sdf_detach_sdf(SEXP internal_name) {
|
| 4798 |
mrmanese |
480 |
const char *iname;
|
| 3446 |
mrmanese |
481 |
int res;
|
|
|
482 |
|
| 3255 |
mrmanese |
483 |
if (!IS_CHARACTER(internal_name)) {
|
| 3684 |
mrmanese |
484 |
error("iname argument is not a string.");
|
| 3255 |
mrmanese |
485 |
}
|
|
|
486 |
|
| 3446 |
mrmanese |
487 |
iname = CHAR_ELT(internal_name, 0);
|
| 3255 |
mrmanese |
488 |
sprintf(g_sql_buf[0], "detach [%s]", iname);
|
|
|
489 |
|
|
|
490 |
res = _sqlite_exec(g_sql_buf[0]);
|
|
|
491 |
res = !_sqlite_error(res);
|
|
|
492 |
|
|
|
493 |
if (res) _delete_sdf2(iname);
|
| 3446 |
mrmanese |
494 |
|
|
|
495 |
return ScalarLogical(res);
|
| 3255 |
mrmanese |
496 |
}
|
| 3307 |
mrmanese |
497 |
|
|
|
498 |
SEXP sdf_rename_sdf(SEXP sdf, SEXP name) {
|
| 4798 |
mrmanese |
499 |
const char *iname, *newname;
|
|
|
500 |
char *path;
|
| 3307 |
mrmanese |
501 |
int res, ret_tmp;
|
|
|
502 |
|
|
|
503 |
iname = SDF_INAME(sdf);
|
|
|
504 |
newname = CHAR_ELT(name, 0);
|
|
|
505 |
|
| 3419 |
mrmanese |
506 |
if (!USE_SDF1(iname, TRUE, FALSE)) return R_NilValue;
|
| 3308 |
mrmanese |
507 |
|
| 3307 |
mrmanese |
508 |
/* check if valid r name */
|
|
|
509 |
if (!_is_r_sym(newname)) {
|
| 3684 |
mrmanese |
510 |
error("%s is not a valid R symbol.", iname);
|
| 3307 |
mrmanese |
511 |
}
|
|
|
512 |
|
|
|
513 |
/* check if sdf already exists */
|
|
|
514 |
if (_sdf_exists2(newname)) { /* name is already taken */
|
| 3684 |
mrmanese |
515 |
error("Error: the name \"%s\" is already taken.", newname);
|
| 3307 |
mrmanese |
516 |
}
|
|
|
517 |
|
| 3324 |
mrmanese |
518 |
/* get path of the sdf file, because we're going to detach it */
|
| 3307 |
mrmanese |
519 |
path = _get_sdf_detail2(iname, SDF_DETAIL_FULLFILENAME);
|
|
|
520 |
if (path == NULL) {
|
| 3684 |
mrmanese |
521 |
error("no sdf named \"%s\" exists.", iname);
|
| 3307 |
mrmanese |
522 |
}
|
|
|
523 |
|
|
|
524 |
/* change name in sdf_attribute */
|
|
|
525 |
sprintf(g_sql_buf[0], "update [%s].sdf_attributes set value='%s' "
|
|
|
526 |
"where attr='name'", iname, newname);
|
|
|
527 |
res = _sqlite_exec(g_sql_buf[0]);
|
|
|
528 |
/* if (_sqlite_error(res)) return R_NilValue; */
|
|
|
529 |
|
|
|
530 |
/* detach and remove sdf from workspace */
|
|
|
531 |
sprintf(g_sql_buf[0], "detach '%s'", iname);
|
|
|
532 |
res = _sqlite_exec(g_sql_buf[0]);
|
|
|
533 |
ret_tmp = !_sqlite_error(res);
|
|
|
534 |
|
|
|
535 |
/* remove from ws, attach and add again to ws using new name */
|
|
|
536 |
if (ret_tmp) {
|
|
|
537 |
_delete_sdf2(iname);
|
|
|
538 |
sprintf(g_sql_buf[0], "attach '%s' as '%s'", path, newname);
|
|
|
539 |
res = _sqlite_exec(g_sql_buf[0]);
|
|
|
540 |
ret_tmp = !_sqlite_error(res);
|
|
|
541 |
|
|
|
542 |
/* TODO: make path relative! */
|
|
|
543 |
_add_sdf1(iname, path);
|
|
|
544 |
}
|
|
|
545 |
|
| 3446 |
mrmanese |
546 |
return ScalarLogical(ret_tmp);
|
| 3307 |
mrmanese |
547 |
}
|
|
|
548 |
|