1 //-< LOCALCLI.CPP >--------------------------------------------------*--------*
2 // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 // (Post Relational Database Management System) * /\| *
4 // * / \ *
5 // Created: 20-Jun-2002 K.A. Knizhnik * / [] \ *
6 // Last update: 20-Jun-2002 K.A. Knizhnik * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Implementation of local C interface to database
9 //-------------------------------------------------------------------*--------*
10
11 #define INSIDE_GIGABASE
12
13 #include "localcli.h"
14 #include "btree.h"
15 #include "rtree.h"
16 #include "symtab.h"
17
18 #ifdef SUPPORT_DATA_ENCRYPTION
19 #include "crypt/crypt_file.h"
20 #endif
21
22 USE_GIGABASE_NAMESPACE
23
24 #ifdef THROW_EXCEPTION_ON_ERROR
25 #define GB_TRY try {
26 #define GB_CATCH } catch (dbException const&) { return cli_runtime_error; }
27 #else
28 #define GB_TRY
29 #define GB_CATCH
30 #endif
31
32
33 dbCLI dbCLI::instance;
34
cli_open(char const * server_url,int max_connect_attempts,int reconnect_timeout_sec,char_t const * user_name,char_t const * password,int pooled_connection)35 int cli_open(char const* server_url,
36 int max_connect_attempts,
37 int reconnect_timeout_sec,
38 char_t const* user_name,
39 char_t const* password,
40 int pooled_connection)
41 {
42 return cli_bad_address;
43 }
44
cli_create(char_t const * databasePath,unsigned transactionCommitDelay,int openAttr,size_t poolSize)45 int cli_create(char_t const* databasePath,
46 unsigned transactionCommitDelay,
47 int openAttr,
48 size_t poolSize)
49 {
50 return dbCLI::instance.create_session(databasePath, transactionCommitDelay, openAttr, poolSize, NULL);
51 }
52
53 #ifdef SUPPORT_DATA_ENCRYPTION
cli_create_encrypted(char_t const * databasePath,unsigned transactionCommitDelay,int openAttr,size_t poolSize,char const * password)54 int cli_create_encrypted(char_t const* databasePath,
55 unsigned transactionCommitDelay,
56 int openAttr,
57 size_t poolSize,
58 char const* password)
59 {
60 return dbCLI::instance.create_session(databasePath, transactionCommitDelay, openAttr, poolSize, password);
61 }
62 #endif
63
create_session(char_t const * databasePath,time_t transactionCommitDelay,int openAttr,size_t poolSize,char const * password)64 int dbCLI::create_session(char_t const* databasePath,
65 time_t transactionCommitDelay,
66 int openAttr,
67 size_t poolSize,
68 char const* password)
69 {
70 dbCriticalSection cs(sessionMutex);
71 dbDatabase* db = NULL;
72 session_desc* s;
73 for (s = active_session_list; s != NULL; s = s->next) {
74 if (STRCMP(s->name, databasePath) == 0) {
75 db = s->db;
76 db->accessCount += 1;
77 break;
78 }
79 }
80 if (db == NULL) {
81 GB_TRY
82 db = new dbDatabase((openAttr & cli_open_multiclient)
83 ? (openAttr & cli_open_readonly)
84 ? dbDatabase::dbMulticlientReadOnly : dbDatabase::dbMulticlientReadWrite
85 : (openAttr & cli_open_readonly)
86 ? dbDatabase::dbReadOnly : dbDatabase::dbAllAccess,
87 poolSize);
88 bool success = false;
89 if (password == NULL) {
90 success = db->open(databasePath, transactionCommitDelay,
91 ((openAttr & cli_open_readonly) ? dbFile::read_only : 0) |
92 ((openAttr & cli_open_truncate) ? dbFile::truncate : 0) |
93 ((openAttr & cli_open_no_buffering) ? dbFile::no_buffering : 0));
94 #ifdef SUPPORT_DATA_ENCRYPTION
95 } else {
96 dbCryptFile* file = new dbCryptFile(password);
97 if (file->open(databasePath,
98 ((openAttr & cli_open_readonly) ? dbFile::read_only : 0) |
99 ((openAttr & cli_open_truncate) ? dbFile::truncate : 0) |
100 ((openAttr & cli_open_no_buffering) ? dbFile::no_buffering : 0)) == dbFile::ok)
101 {
102 success = db->open(file, transactionCommitDelay, true);
103 }
104 #endif
105 }
106 if (!success) {
107 delete db;
108 return cli_database_not_found;
109 }
110 if (openAttr & cli_open_do_not_reuse_oids_on_close) {
111 db->disableOidReuseOnClose();
112 }
113 db->beginTransaction(dbUpdateLock);
114 dbGetTie tie;
115 dbTable* table = (dbTable*)db->getRow(tie, dbMetaTableId);
116 dbTableDescriptor* metatable = new dbTableDescriptor(table);
117 db->linkTable(metatable, dbMetaTableId);
118 oid_t tableId = table->firstRow;
119 while (tableId != 0) {
120 table = (dbTable*)db->getRow(tie, tableId);
121 dbTableDescriptor* desc;
122 for (desc = db->tables; desc != NULL && desc->tableId != tableId; desc = desc->nextDbTable);
123 if (desc == NULL) {
124 desc = new dbTableDescriptor(table);
125 db->linkTable(desc, tableId);
126 desc->setFlags();
127 }
128 tableId = table->next;
129 }
130 if (!db->completeDescriptorsInitialization()) {
131 db->close();
132 delete db;
133 return cli_table_not_found;
134 }
135 db->accessCount = 1;
136 db->commit();
137 GB_CATCH
138 }
139 s = sessions.allocate();
140 s->db = db;
141 s->name = new char_t[STRLEN(databasePath) + 1];
142 STRCPY(s->name, databasePath);
143 s->stmts = NULL;
144 s->next = active_session_list;
145 s->existed_tables = NULL;
146 s->dropped_tables = NULL;
147 active_session_list = s;
148 return s->id;
149 }
150
151
cli_close(int session)152 int cli_close(int session)
153 {
154 return dbCLI::instance.close(session);
155 }
156
close(int session)157 int dbCLI::close(int session)
158 {
159 dbCriticalSection cs(sessionMutex);
160 statement_desc *stmt, *next;
161 session_desc* s = sessions.get(session);
162 if (s == NULL) {
163 return cli_bad_descriptor;
164 }
165 dbCriticalSection cs2(s->mutex);
166 for (stmt = s->stmts; stmt != NULL; stmt = next) {
167 next = stmt->next;
168 release_statement(stmt);
169 }
170 if (--s->db->accessCount == 0) {
171 GB_TRY
172 s->db->close();
173 delete s->db;
174 GB_CATCH
175 }
176 while (s->dropped_tables != NULL) {
177 dbTableDescriptor* next = s->dropped_tables->nextDbTable;
178 delete s->dropped_tables;
179 s->dropped_tables = next;
180 }
181 session_desc** spp;
182 for (spp = &active_session_list; *spp != s; spp = &(*spp)->next);
183 *spp = s->next;
184 delete[] s->name;
185 sessions.free(s);
186
187 return cli_ok;
188 }
189
cli_statement(int session,char_t const * sql)190 int cli_statement(int session, char_t const* sql)
191 {
192 return dbCLI::instance.create_statement(session, sql);
193 }
194
create_statement(int session,char_t const * sql)195 int dbCLI::create_statement(int session, char_t const* sql)
196 {
197 session_desc* s = sessions.get(session);
198 if (s == NULL) {
199 return cli_bad_descriptor;
200 }
201 statement_desc* stmt = statements.allocate();
202 stmt->sql.put(STRLEN(sql)+1);
203 STRCPY(stmt->sql.base(), sql);
204 stmt->columns = NULL;
205 stmt->params = NULL;
206 stmt->session = s;
207 stmt->cursor_type = cli_cursor_view_only;
208 stmt->first_fetch = true;
209 stmt->prepared = false;
210 stmt->n_params = 0;
211 stmt->n_columns = 0;
212 stmt->n_autoincremented_columns = 0;
213 stmt->oid = 0;
214 stmt->updated = false;
215 stmt->record_struct = NULL;
216 stmt->table = NULL;
217 stmt->cursor.db = NULL;
218 {
219 dbCriticalSection cs(s->mutex);
220 stmt->next = s->stmts;
221 s->stmts = stmt;
222 }
223 char_t const* p = sql;
224 parameter_binding** last = &stmt->params;
225 while (*p != '\0') {
226 if (*p == '\'') {
227 do {
228 do {
229 p += 1;
230 } while (*p != '\0' && *p != '\'');
231 if (*p == '\0') {
232 *last = NULL;
233 free_statement(stmt);
234 return cli_bad_statement;
235 }
236 } while (*++p == '\'');
237 } else if (*p == '%') {
238 stmt->n_params += 1;
239 char_t const* q = p++;
240 while (ISALNUM(*p) || *p == '_') p += 1;
241 if (*p == '%') {
242 *last = NULL;
243 free_statement(stmt);
244 return cli_bad_statement;
245 }
246 parameter_binding* pb = parameter_allocator.allocate();
247 int len = (int)(p - q);
248 pb->name = new char_t[len+1];
249 memcpy(pb->name, q, len*sizeof(char_t));
250 pb->name[len] = '\0';
251 *last = pb;
252 last = &pb->next;
253 pb->var_ptr = NULL;
254 } else {
255 p += 1;
256 }
257 }
258 *last = NULL;
259 return stmt->id;
260 }
261
cli_parameter(int statement,char_t const * param_name,int var_type,void * var_ptr)262 int cli_parameter(int statement,
263 char_t const* param_name,
264 int var_type,
265 void* var_ptr)
266 {
267 return dbCLI::instance.bind_parameter(statement, param_name, var_type, var_ptr);
268 }
269
270
bind_parameter(int statement,char_t const * param_name,int var_type,void * var_ptr)271 int dbCLI::bind_parameter(int statement,
272 char_t const* param_name,
273 int var_type,
274 void* var_ptr)
275 {
276 if ((((unsigned)var_type > cli_array_of_oid
277 && var_type != cli_array_of_int4
278 && var_type != cli_array_of_int8
279 && var_type != cli_rectangle
280 && var_type != cli_datetime)
281 || var_type == cli_decimal))
282 {
283 return cli_unsupported_type;
284 }
285 statement_desc* s = statements.get(statement);
286 if (s == NULL) {
287 return cli_bad_descriptor;
288 }
289 s->prepared = false;
290 for (parameter_binding* pb = s->params; pb != NULL; pb = pb->next) {
291 if (STRCMP(pb->name, param_name) == 0) {
292 pb->var_ptr = var_ptr;
293 pb->var_type = var_type;
294 return cli_ok;
295 }
296 }
297 return cli_parameter_not_found;
298 }
299
cli_column(int statement,char_t const * column_name,int var_type,int * var_len,void * var_ptr)300 int cli_column(int statement,
301 char_t const* column_name,
302 int var_type,
303 int* var_len,
304 void* var_ptr)
305 {
306 return dbCLI::instance.bind_column(statement, column_name, var_type, var_len, var_ptr);
307 }
308
bind_column(int statement,char_t const * column_name,int var_type,int * var_len,void * var_ptr)309 int dbCLI::bind_column(int statement,
310 char_t const* column_name,
311 int var_type,
312 int* var_len,
313 void* var_ptr)
314 {
315 statement_desc* s = statements.get(statement);
316 if (s == NULL) {
317 return cli_bad_descriptor;
318 }
319 if (var_type == cli_decimal || var_type == cli_cstring || var_type == cli_array_of_decimal
320 || (unsigned)var_type >= cli_unknown)
321 {
322 return cli_unsupported_type;
323 }
324 s->prepared = false;
325 if (var_type == cli_autoincrement) {
326 s->n_autoincremented_columns += 1;
327 }
328 column_binding* cb = column_allocator.allocate();
329 cb->name = new char_t[STRLEN(column_name) + 1];
330 cb->next = s->columns;
331 s->columns = cb;
332 s->n_columns += 1;
333 STRCPY(cb->name, column_name);
334 cb->var_type = var_type;
335 cb->var_len = var_len;
336 cb->var_ptr = var_ptr;
337 cb->set_fnc = NULL;
338 cb->get_fnc = NULL;
339 return cli_ok;
340 }
341
cli_array_column_ex(int statement,char_t const * column_name,int var_type,void * var_ptr,cli_column_set_ex set,cli_column_get_ex get,void * user_data)342 int cli_array_column_ex(int statement,
343 char_t const* column_name,
344 int var_type,
345 void* var_ptr,
346 cli_column_set_ex set,
347 cli_column_get_ex get,
348 void* user_data)
349 {
350 return dbCLI::instance.bind_array_column(statement, column_name, var_type, var_ptr, set, get, user_data);
351 }
352
353
cli_array_column(int statement,char_t const * column_name,int var_type,void * var_ptr,cli_column_set set,cli_column_get get)354 int cli_array_column(int statement,
355 char_t const* column_name,
356 int var_type,
357 void* var_ptr,
358 cli_column_set set,
359 cli_column_get get)
360 {
361 return cli_array_column_ex(statement, column_name, var_type, var_ptr,
362 (cli_column_set_ex)set, (cli_column_get_ex)get, NULL);
363 }
364
365
bind_array_column(int statement,char_t const * column_name,int var_type,void * var_ptr,cli_column_set_ex set,cli_column_get_ex get,void * user_data)366 int dbCLI::bind_array_column(int statement,
367 char_t const* column_name,
368 int var_type,
369 void* var_ptr,
370 cli_column_set_ex set,
371 cli_column_get_ex get,
372 void* user_data)
373 {
374 statement_desc* s = statements.get(statement);
375 if (s == NULL) {
376 return cli_bad_descriptor;
377 }
378 if (var_type < cli_asciiz || var_type > cli_array_of_string || var_type == cli_array_of_decimal) {
379 return cli_unsupported_type;
380 }
381 s->prepared = false;
382 column_binding* cb = column_allocator.allocate();
383 cb->name = new char_t[STRLEN(column_name) + 1];
384 cb->next = s->columns;
385 s->columns = cb;
386 s->n_columns += 1;
387 STRCPY(cb->name, column_name);
388 cb->var_type = var_type;
389 cb->var_len = NULL;
390 cb->var_ptr = var_ptr;
391 cb->set_fnc = set;
392 cb->get_fnc = get;
393 cb->user_data = user_data;
394 return cli_ok;
395 }
396
match_columns(char_t const * table_name,statement_desc * stmt)397 int dbCLI::match_columns(char_t const* table_name, statement_desc* stmt)
398 {
399 stmt->table = stmt->session->db->findTable(table_name);
400 if (stmt->table == NULL) {
401 return cli_table_not_found;
402 }
403 for (column_binding* cb = stmt->columns; cb != NULL; cb = cb->next) {
404 cb->field = stmt->table->find(cb->name);
405 if (cb->field == NULL) {
406 return cli_column_not_found;
407 }
408 }
409 return cli_ok;
410 }
411
cli_fetch(int statement,int for_update)412 int cli_fetch(int statement, int for_update)
413 {
414 cli_cardinality_t n_fetched_records = 0;
415 int rc = dbCLI::instance.fetch(statement, for_update, &n_fetched_records);
416 return rc < 0 ? rc : (int)n_fetched_records;
417 }
418
cli_fetch_ex(int statement,int for_update,cli_cardinality_t * n_fetched_records)419 int cli_fetch_ex(int statement, int for_update, cli_cardinality_t* n_fetched_records)
420 {
421 return dbCLI::instance.fetch(statement, for_update, n_fetched_records);
422 }
423
fetch(int statement,int cursor_type,cli_cardinality_t * n_fetched_records)424 int dbCLI::fetch(int statement, int cursor_type, cli_cardinality_t* n_fetched_records)
425 {
426 statement_desc* stmt = statements.get(statement);
427 if (stmt == NULL) {
428 return cli_bad_descriptor;
429 }
430 stmt->cursor_type = cursor_type;
431 stmt->oid = 0;
432 stmt->first_fetch = true;
433 if (!stmt->prepared) {
434 int tkn;
435 sql_scanner scanner(stmt->sql.base());
436 if (scanner.get() != tkn_select) {
437 return cli_bad_statement;
438 }
439 if ((tkn = scanner.get()) == tkn_all) {
440 tkn = scanner.get();
441 }
442 if (tkn == tkn_from && scanner.get() == tkn_ident) {
443 int rc = match_columns(scanner.identifier(), stmt);
444 if (rc != cli_ok) {
445 return rc;
446 }
447 } else {
448 return cli_bad_statement;
449 }
450 char_t* p = scanner.current_position(), *q = p;
451 parameter_binding* pb = stmt->params;
452 stmt->query.reset();
453 while (*p != '\0') {
454 if (*p == '\'') {
455 do {
456 do {
457 p += 1;
458 } while (*p != '\0' && *p != '\'');
459 if (*p == '\0') {
460 return cli_bad_statement;
461 }
462 } while (*++p == '\'');
463 } else if (*p == '%') {
464 if (p != q) {
465 *p = '\0';
466 stmt->query.append(dbQueryElement::qExpression, q);
467 }
468 if (pb->var_ptr == NULL) {
469 return cli_unbound_parameter;
470 }
471 switch(pb->var_type) {
472 case cli_oid:
473 stmt->query.append(dbQueryElement::qVarReference, pb->var_ptr);
474 break;
475 case cli_bool:
476 stmt->query.append(dbQueryElement::qVarBool, pb->var_ptr);
477 break;
478 case cli_int1:
479 stmt->query.append(dbQueryElement::qVarInt1, pb->var_ptr);
480 break;
481 case cli_int2:
482 stmt->query.append(dbQueryElement::qVarInt2, pb->var_ptr);
483 break;
484 case cli_int4:
485 stmt->query.append(dbQueryElement::qVarInt4, pb->var_ptr);
486 break;
487 case cli_int8:
488 stmt->query.append(dbQueryElement::qVarInt8, pb->var_ptr);
489 break;
490 case cli_datetime:
491 stmt->query.append(sizeof(cli_time_t) == 4
492 ? dbQueryElement::qVarInt4 : dbQueryElement::qVarInt8,
493 pb->var_ptr);
494 break;
495 case cli_real4:
496 stmt->query.append(dbQueryElement::qVarReal4, pb->var_ptr);
497 break;
498 case cli_real8:
499 stmt->query.append(dbQueryElement::qVarReal8, pb->var_ptr);
500 break;
501 case cli_asciiz:
502 stmt->query.append(dbQueryElement::qVarString, pb->var_ptr);
503 break;
504 case cli_pasciiz:
505 stmt->query.append(dbQueryElement::qVarStringPtr, pb->var_ptr);
506 break;
507 case cli_array_of_oid:
508 stmt->query.append(dbQueryElement::qVarArrayOfRef, pb->var_ptr);
509 break;
510 case cli_array_of_int4:
511 stmt->query.append(dbQueryElement::qVarArrayOfInt4, pb->var_ptr);
512 break;
513 case cli_array_of_int8:
514 stmt->query.append(dbQueryElement::qVarArrayOfInt8, pb->var_ptr);
515 break;
516 case cli_rectangle:
517 stmt->query.append(dbQueryElement::qVarRectangle, pb->var_ptr);
518 break;
519 default:
520 return cli_unsupported_type;
521
522 }
523 while (ISALNUM(*++p));
524 q = p;
525 pb = pb->next;
526 } else {
527 p += 1;
528 }
529 }
530 if (p != q) {
531 stmt->query.append(dbQueryElement::qExpression, q);
532 }
533 stmt->prepared = true;
534 }
535 stmt->cursor.setTable(stmt->table);
536 stmt->cursor.reset();
537 GB_TRY
538 *n_fetched_records = stmt->cursor.select(stmt->query, (dbCursorType)cursor_type);
539 return cli_ok;
540 #ifdef THROW_EXCEPTION_ON_ERROR
541 } catch (dbException const& x) {
542 return (x.getErrCode() == dbDatabase::QueryError)
543 ? cli_bad_statement : cli_runtime_error;
544 }
545 #endif
546 }
547
548
549 int dbCLI::fetch_columns(statement_desc* stmt)
550 {
551 stmt->first_fetch = false;
552 if (stmt->cursor.isEmpty()) {
553 return cli_not_found;
554 }
555 dbGetTie tie;
556 GB_TRY
557 stmt->updated = false;
558 if (stmt->record_struct != NULL) {
559 stmt->cursor.fetch();
560 return cli_ok;
561 }
562 char* data = (char*)stmt->session->db->getRow(tie, stmt->cursor.currId);
563 for (column_binding* cb = stmt->columns; cb != NULL; cb = cb->next) {
564 char* src = data + cb->field->dbsOffs;
565 char* dst = (char*)cb->var_ptr;
566 switch (cb->field->type) {
567 case dbField::tpBool:
568 switch (cb->var_type) {
569 case cli_bool:
570 *(cli_bool_t*)dst = *(bool*)src;
571 continue;
572 case cli_int1:
573 *(cli_int1_t*)dst = *(bool*)src ? 1 : 0;
574 continue;
575 case cli_int2:
576 *(cli_int2_t*)dst = *(bool*)src ? 1 : 0;
577 continue;
578 case cli_int4:
579 *(cli_int4_t*)dst = *(bool*)src ? 1 : 0;
580 continue;
581 case cli_int8:
582 *(db_int8*)dst = *(bool*)src ? 1 : 0;
583 continue;
584 case cli_datetime:
585 *(cli_time_t*)dst = *(bool*)src ? 1 : 0;
586 continue;
587 case cli_real4:
588 *(cli_real4_t*)dst = (cli_real4_t)(*(bool*)src ? 1 : 0);
589 continue;
590 case cli_real8:
591 *(cli_real8_t*)dst = *(bool*)src ? 1 : 0;
592 continue;
593 }
594 break;
595 case dbField::tpInt1:
596 switch (cb->var_type) {
597 case cli_bool:
598 *(cli_bool_t*)dst = *(int1*)src != 0;
599 continue;
600 case cli_int1:
601 *(cli_int1_t*)dst = *(int1*)src;
602 continue;
603 case cli_int2:
604 *(cli_int2_t*)dst = *(int1*)src;
605 continue;
606 case cli_int4:
607 *(cli_int4_t*)dst = *(int1*)src;
608 continue;
609 case cli_int8:
610 *(db_int8*)dst = *(int1*)src;
611 continue;
612 case cli_datetime:
613 *(cli_time_t*)dst = *(int1*)src;
614 continue;
615 case cli_real4:
616 *(cli_real4_t*)dst = *(int1*)src;
617 continue;
618 case cli_real8:
619 *(cli_real8_t*)dst = *(int1*)src;
620 continue;
621 }
622 break;
623 case dbField::tpInt2:
624 switch (cb->var_type) {
625 case cli_bool:
626 *(cli_bool_t*)dst = *(int2*)src != 0;
627 continue;
628 case cli_int1:
629 *(cli_int1_t*)dst = (int1)*(int2*)src;
630 continue;
631 case cli_int2:
632 *(cli_int2_t*)dst = *(int2*)src;
633 continue;
634 case cli_int4:
635 *(cli_int4_t*)dst = *(int2*)src;
636 continue;
637 case cli_int8:
638 *(db_int8*)dst = *(int2*)src;
639 continue;
640 case cli_datetime:
641 *(cli_time_t*)dst = *(int2*)src;
642 continue;
643 case cli_real4:
644 *(cli_real4_t*)dst = *(int2*)src;
645 continue;
646 case cli_real8:
647 *(cli_real8_t*)dst = *(int2*)src;
648 continue;
649 }
650 break;
651 case dbField::tpInt4:
652 switch (cb->var_type) {
653 case cli_bool:
654 *(cli_bool_t*)dst = *(int4*)src != 0;
655 continue;
656 case cli_int1:
657 *(cli_int1_t*)dst = (cli_int1_t)*(int4*)src;
658 continue;
659 case cli_int2:
660 *(cli_int2_t*)dst = (cli_int2_t)*(int4*)src;
661 continue;
662 case cli_int4:
663 case cli_autoincrement:
664 *(cli_int4_t*)dst = *(int4*)src;
665 continue;
666 case cli_int8:
667 *(db_int8*)dst = *(int4*)src;
668 continue;
669 case cli_datetime:
670 *(cli_time_t*)dst = *(int4*)src;
671 continue;
672 case cli_real4:
673 *(cli_real4_t*)dst = (cli_real4_t)*(int4*)src;
674 continue;
675 case cli_real8:
676 *(cli_real8_t*)dst = *(int4*)src;
677 continue;
678 }
679 break;
680 case dbField::tpInt8:
681 switch (cb->var_type) {
682 case cli_bool:
683 *(cli_bool_t*)dst = *(db_int8*)src != 0;
684 continue;
685 case cli_int1:
686 *(cli_int1_t*)dst = (cli_int1_t)*(db_int8*)src;
687 continue;
688 case cli_int2:
689 *(cli_int2_t*)dst = (cli_int2_t)*(db_int8*)src;
690 continue;
691 case cli_int4:
692 *(cli_int4_t*)dst = (cli_int4_t)*(db_int8*)src;
693 continue;
694 case cli_int8:
695 *(db_int8*)dst = *(db_int8*)src;
696 continue;
697 case cli_datetime:
698 *(cli_time_t*)dst = (cli_time_t)*(db_int8*)src;
699 continue;
700 case cli_real4:
701 *(cli_real4_t*)dst = (cli_real4_t)*(db_int8*)src;
702 continue;
703 case cli_real8:
704 *(cli_real8_t*)dst = (cli_real8_t)*(db_int8*)src;
705 continue;
706 }
707 break;
708 case dbField::tpReal4:
709 switch (cb->var_type) {
710 case cli_bool:
711 *(cli_bool_t*)dst = *(real4*)src != 0;
712 continue;
713 case cli_int1:
714 *(cli_int1_t*)dst = (cli_int1_t)*(real4*)src;
715 continue;
716 case cli_int2:
717 *(cli_int2_t*)dst = (cli_int2_t)*(real4*)src;
718 continue;
719 case cli_int4:
720 *(cli_int4_t*)dst = (cli_int4_t)*(real4*)src;
721 continue;
722 case cli_int8:
723 *(db_int8*)dst = (db_int8)*(real4*)src;
724 continue;
725 case cli_datetime:
726 *(cli_time_t*)dst = (cli_time_t)*(real4*)src;
727 continue;
728 case cli_real4:
729 *(cli_real4_t*)dst = *(real4*)src;
730 continue;
731 case cli_real8:
732 *(cli_real8_t*)dst = *(real4*)src;
733 continue;
734 }
735 break;
736 case dbField::tpReal8:
737 switch (cb->var_type) {
738 case cli_bool:
739 *(cli_bool_t*)dst = *(real8*)src != 0;
740 continue;
741 case cli_int1:
742 *(cli_int1_t*)dst = (cli_int1_t)*(real8*)src;
743 continue;
744 case cli_int2:
745 *(cli_int2_t*)dst = (cli_int2_t)*(real8*)src;
746 continue;
747 case cli_int4:
748 *(cli_int4_t*)dst = (cli_int4_t)*(real8*)src;
749 continue;
750 case cli_int8:
751 *(db_int8*)dst = (db_int8)*(real8*)src;
752 continue;
753 case cli_datetime:
754 *(cli_time_t*)dst = (cli_time_t)*(real8*)src;
755 continue;
756 case cli_real4:
757 *(cli_real4_t*)dst = (real4)*(real8*)src;
758 continue;
759 case cli_real8:
760 *(cli_real8_t*)dst = *(real8*)src;
761 continue;
762 }
763 break;
764 case dbField::tpReference:
765 if (cb->var_type == cli_oid) {
766 *(cli_oid_t*)dst = *(oid_t*)src;
767 continue;
768 }
769 break;
770 case dbField::tpRectangle:
771 if (cb->var_type == cli_rectangle) {
772 *(cli_rectangle_t*)dst = *(cli_rectangle_t*)src;
773 continue;
774 }
775 break;
776 case dbField::tpString:
777 if (cb->var_type == cli_asciiz || cb->var_type == cli_pasciiz) {
778 if (cb->var_type == cli_pasciiz) {
779 dst = *(char**)dst;
780 }
781 dbVarying* v = (dbVarying*)src;
782 int size = v->size;
783 if (cb->set_fnc != NULL) {
784 dst = (char*)cb->set_fnc(cli_asciiz, dst, size,
785 cb->name, stmt->id, data + v->offs, cb->user_data);
786 if (dst != NULL) {
787 memcpy(dst, data + v->offs, size*sizeof(char_t));
788 }
789 } else {
790 int n = size;
791 if (cb->var_len != NULL) {
792 if (n > *cb->var_len) {
793 n = *cb->var_len;
794 }
795 *cb->var_len = size;
796 }
797 memcpy(dst, data + v->offs, n*sizeof(char_t));
798 }
799 continue;
800 }
801 break;
802 case dbField::tpArray:
803 if (cb->var_type >= cli_array_of_oid && cb->var_type <= cli_array_of_string && cb->var_type != cli_array_of_decimal)
804 {
805 dbVarying* v = (dbVarying*)src;
806 int n = v->size;
807 src = data + v->offs;
808 if (cb->set_fnc != NULL) {
809 dst = (char*)cb->set_fnc(cb->var_type, dst, n,
810 cb->name, stmt->id, src, cb->user_data);
811 if (dst == NULL) {
812 continue;
813 }
814 } else {
815 int size = n;
816 if (cb->var_len != NULL) {
817 if (n > *cb->var_len) {
818 n = *cb->var_len;
819 }
820 *cb->var_len = size;
821 }
822 }
823 switch (cb->field->components->type) {
824 case dbField::tpBool:
825 if (cb->var_type == cli_array_of_bool) {
826 cli_bool_t* dst_elem = (cli_bool_t*)dst;
827 bool* src_elem = (bool*)src;
828 while (--n >= 0) *dst_elem++ = *src_elem++;
829 continue;
830 }
831 break;
832 case dbField::tpInt1:
833 if (cb->var_type == cli_array_of_int1) {
834 cli_int1_t* dst_elem = (cli_int1_t*)dst;
835 int1* src_elem = (int1*)src;
836 while (--n >= 0) *dst_elem++ = *src_elem++;
837 continue;
838 }
839 break;
840 case dbField::tpInt2:
841 if (cb->var_type == cli_array_of_int2) {
842 cli_int2_t* dst_elem = (cli_int2_t*)dst;
843 int2* src_elem = (int2*)src;
844 while (--n >= 0) *dst_elem++ = *src_elem++;
845 continue;
846 }
847 break;
848 case dbField::tpInt4:
849 if (cb->var_type == cli_array_of_int4) {
850 cli_int4_t* dst_elem = (cli_int4_t*)dst;
851 int4* src_elem = (int4*)src;
852 while (--n >= 0) *dst_elem++ = *src_elem++;
853 continue;
854 }
855 break;
856 case dbField::tpInt8:
857 if (cb->var_type == cli_array_of_int8) {
858 cli_int8_t* dst_elem = (cli_int8_t*)dst;
859 db_int8* src_elem = (db_int8*)src;
860 while (--n >= 0) *dst_elem++ = *src_elem++;
861 continue;
862 }
863 break;
864 case dbField::tpReal4:
865 if (cb->var_type == cli_array_of_real4) {
866 cli_real4_t* dst_elem = (cli_real4_t*)dst;
867 real4* src_elem = (real4*)src;
868 while (--n >= 0) *dst_elem++ = *src_elem++;
869 continue;
870 }
871 break;
872 case dbField::tpReal8:
873 if (cb->var_type == cli_array_of_real8) {
874 cli_real8_t* dst_elem = (cli_real8_t*)dst;
875 real8* src_elem = (real8*)src;
876 while (--n >= 0) *dst_elem++ = *src_elem++;
877 continue;
878 }
879 break;
880 case dbField::tpReference:
881 if (cb->var_type == cli_array_of_oid) {
882 cli_oid_t* dst_elem = (cli_oid_t*)dst;
883 oid_t* src_elem = (oid_t*)src;
884 while (--n >= 0) *dst_elem++ = *src_elem++;
885 continue;
886 }
887 break;
888 case dbField::tpString:
889 if (cb->var_type == cli_array_of_string) {
890 char_t** dst_elem = (char_t**)dst;
891 dbVarying* src_elem = (dbVarying*)src;
892 while (--n >= 0) {
893 *dst_elem++ = (char_t*)((char*)src_elem + src_elem->offs);
894 src_elem += 1;
895 }
896 continue;
897 }
898 }
899 }
900 }
901 return cli_unsupported_type;
902 }
903 GB_CATCH
904 return cli_ok;
905 }
906
907
908 int dbCLI::store_columns(char* data, statement_desc* stmt, bool insert)
909 {
910 for (column_binding* cb = stmt->columns; cb != NULL; cb = cb->next)
911 {
912 char* dst = data + cb->field->appOffs;
913 char* src = (char*)cb->var_ptr;
914 switch (cb->field->type) {
915 case dbField::tpBool:
916 switch (cb->var_type) {
917 case cli_bool:
918 *(bool*)dst = *(cli_bool_t*)src;
919 continue;
920 case cli_int1:
921 *(bool*)dst = *(cli_int1_t*)src != 0;
922 continue;
923 case cli_int2:
924 *(bool*)dst = *(cli_int2_t*)src != 0;
925 continue;
926 case cli_int4:
927 *(bool*)dst = *(cli_int4_t*)src != 0;
928 continue;
929 case cli_int8:
930 *(bool*)dst = *(db_int8*)src != 0;
931 continue;
932 case cli_datetime:
933 *(bool*)dst = *(cli_time_t*)src != 0;
934 continue;
935 case cli_real4:
936 *(bool*)dst = *(cli_real4_t*)src != 0;
937 continue;
938 case cli_real8:
939 *(bool*)dst = *(cli_real8_t*)src != 0;
940 continue;
941 }
942 break;
943 case dbField::tpInt1:
944 switch (cb->var_type) {
945 case cli_bool:
946 *(int1*)dst = *(cli_bool_t*)src ? 1 : 0;
947 continue;
948 case cli_int1:
949 *(int1*)dst = *(cli_int1_t*)src;
950 continue;
951 case cli_int2:
952 *(int1*)dst = (int1)*(cli_int2_t*)src;
953 continue;
954 case cli_int4:
955 *(int1*)dst = (int1)*(cli_int4_t*)src;
956 continue;
957 case cli_int8:
958 *(int1*)dst = (int1)*(db_int8*)src;
959 continue;
960 case cli_datetime:
961 *(int1*)dst = (int1)*(cli_time_t*)src;
962 continue;
963 case cli_real4:
964 *(int1*)dst = (int1)*(cli_real4_t*)src;
965 continue;
966 case cli_real8:
967 *(int1*)dst = (int1)*(cli_real8_t*)src;
968 continue;
969 }
970 break;
971 case dbField::tpInt2:
972 switch (cb->var_type) {
973 case cli_bool:
974 *(int2*)dst = *(cli_bool_t*)src ? 1 : 0;
975 continue;
976 case cli_int1:
977 *(int2*)dst = *(cli_int1_t*)src;
978 continue;
979 case cli_int2:
980 *(int2*)dst = *(cli_int2_t*)src;
981 continue;
982 case cli_int4:
983 *(int2*)dst = (int2)*(cli_int4_t*)src;
984 continue;
985 case cli_int8:
986 *(int2*)dst = (int2)*(db_int8*)src;
987 continue;
988 case cli_datetime:
989 *(int2*)dst = (int2)*(cli_time_t*)src;
990 continue;
991 case cli_real4:
992 *(int2*)dst = (int2)*(cli_real4_t*)src;
993 continue;
994 case cli_real8:
995 *(int2*)dst = (int2)*(cli_real8_t*)src;
996 continue;
997 }
998 break;
999 case dbField::tpInt4:
1000 switch (cb->var_type) {
1001 case cli_bool:
1002 *(int4*)dst = *(cli_bool_t*)src ? 1 : 0;
1003 continue;
1004 case cli_int1:
1005 *(int4*)dst = *(cli_int1_t*)src;
1006 continue;
1007 case cli_int2:
1008 *(int4*)dst = *(cli_int2_t*)src;
1009 continue;
1010 case cli_autoincrement:
1011 #ifdef AUTOINCREMENT_SUPPORT
1012 if (insert) {
1013 *(int4*)dst = cb->field->defTable->autoincrementCount+1;
1014 }
1015 #endif
1016 continue;
1017 case cli_int4:
1018 *(int4*)dst = *(cli_int4_t*)src;
1019 continue;
1020 case cli_int8:
1021 *(int4*)dst = (int4)*(db_int8*)src;
1022 continue;
1023 case cli_datetime:
1024 *(int4*)dst = (int4)*(cli_time_t*)src;
1025 continue;
1026 case cli_real4:
1027 *(int4*)dst = (int4)*(cli_real4_t*)src;
1028 continue;
1029 case cli_real8:
1030 *(int4*)dst = (int4)*(cli_real8_t*)src;
1031 continue;
1032 }
1033 break;
1034 case dbField::tpInt8:
1035 switch (cb->var_type) {
1036 case cli_bool:
1037 *(db_int8*)dst = *(cli_bool_t*)src ? 1 : 0;
1038 continue;
1039 case cli_int1:
1040 *(db_int8*)dst = *(cli_int1_t*)src;
1041 continue;
1042 case cli_int2:
1043 *(db_int8*)dst = *(cli_int2_t*)src;
1044 continue;
1045 case cli_int4:
1046 *(db_int8*)dst = *(cli_int4_t*)src;
1047 continue;
1048 case cli_int8:
1049 *(db_int8*)dst = *(db_int8*)src;
1050 continue;
1051 case cli_datetime:
1052 *(db_int8*)dst = (db_int8)*(cli_time_t*)src;
1053 continue;
1054 case cli_real4:
1055 *(db_int8*)dst = (db_int8)*(cli_real4_t*)src;
1056 continue;
1057 case cli_real8:
1058 *(db_int8*)dst = (db_int8)*(cli_real8_t*)src;
1059 continue;
1060 }
1061 break;
1062 case dbField::tpReal4:
1063 switch (cb->var_type) {
1064 case cli_bool:
1065 *(real4*)dst = (real4)(*(cli_bool_t*)src ? 1 : 0);
1066 continue;
1067 case cli_int1:
1068 *(real4*)dst = *(cli_int1_t*)src;
1069 continue;
1070 case cli_int2:
1071 *(real4*)dst = *(cli_int2_t*)src;
1072 continue;
1073 case cli_int4:
1074 *(real4*)dst = (real4)(*(cli_int4_t*)src);
1075 continue;
1076 case cli_int8:
1077 *(real4*)dst = (real4)*(db_int8*)src;
1078 continue;
1079 case cli_datetime:
1080 *(real4*)dst = (real4)*(cli_time_t*)src;
1081 continue;
1082 case cli_real4:
1083 *(real4*)dst = *(cli_real4_t*)src;
1084 continue;
1085 case cli_real8:
1086 *(real4*)dst = (real4)*(cli_real8_t*)src;
1087 continue;
1088 }
1089 break;
1090 case dbField::tpReal8:
1091 switch (cb->var_type) {
1092 case cli_bool:
1093 *(real8*)dst = *(cli_bool_t*)src ? 1 : 0;
1094 continue;
1095 case cli_int1:
1096 *(real8*)dst = *(cli_int1_t*)src;
1097 continue;
1098 case cli_int2:
1099 *(real8*)dst = *(cli_int2_t*)src;
1100 continue;
1101 case cli_int4:
1102 *(real8*)dst = *(cli_int4_t*)src;
1103 continue;
1104 case cli_int8:
1105 *(real8*)dst = (real8)*(db_int8*)src;
1106 continue;
1107 case cli_datetime:
1108 *(real8*)dst = (real8)*(cli_time_t*)src;
1109 continue;
1110 case cli_real4:
1111 *(real8*)dst = *(cli_real4_t*)src;
1112 continue;
1113 case cli_real8:
1114 *(real8*)dst = *(cli_real8_t*)src;
1115 continue;
1116 }
1117 break;
1118 case dbField::tpReference:
1119 if (cb->var_type == cli_oid) {
1120 *(oid_t*)dst = *(cli_oid_t*)src;
1121 continue;
1122 }
1123 break;
1124 case dbField::tpRectangle:
1125 if (cb->var_type == cli_rectangle) {
1126 *(cli_rectangle_t*)dst = *(cli_rectangle_t*)src;
1127 continue;
1128 }
1129 break;
1130 case dbField::tpString:
1131 if (cb->var_type == cli_pasciiz) {
1132 *(char**)dst = *(char**)src;
1133 continue;
1134 } else if (cb->var_type == cli_asciiz) {
1135 if (cb->get_fnc != NULL) {
1136 int len;
1137 src = (char*)cb->get_fnc(cb->var_type, src, &len,
1138 cb->name, stmt->id, cb->user_data);
1139 }
1140 *(char**)dst = src;
1141 continue;
1142 }
1143 break;
1144 case dbField::tpArray:
1145 if (cb->var_type >= cli_array_of_oid && cb->var_type <= cli_array_of_string && cb->var_type != cli_array_of_decimal)
1146 {
1147 int size = 0;
1148 if (cb->get_fnc != NULL) {
1149 src = (char*)cb->get_fnc(cb->var_type, src, &size,
1150 cb->name, stmt->id, cb->user_data);
1151 } else {
1152 if (cb->var_len != NULL) {
1153 size = *cb->var_len;
1154 } else {
1155 return cli_incompatible_type;
1156 }
1157 }
1158 if (cb->var_type == cli_array_of_string) {
1159 if (cb->field->components->type != dbField::tpString) {
1160 return cli_incompatible_type;
1161 }
1162 } else if ((size_t)sizeof_type[cb->var_type - cli_array_of_oid] != cb->field->components->appSize) {
1163 return cli_incompatible_type;
1164 }
1165 cb->field->arrayAllocator((dbAnyArray*)dst, src, size);
1166 continue;
1167 }
1168 }
1169 return cli_unsupported_type;
1170 }
1171 return cli_ok;
1172 }
1173
1174
1175
1176 int cli_insert(int statement, cli_oid_t* oid)
1177 {
1178 return dbCLI::instance.insert(statement, oid, false);
1179 }
1180
1181 int cli_batch_insert(int statement, cli_oid_t* oid)
1182 {
1183 return dbCLI::instance.insert(statement, oid, true);
1184 }
1185
1186 int dbCLI::insert(int statement, cli_oid_t* oid, bool batch)
1187 {
1188 statement_desc* stmt = statements.get(statement);
1189 if (stmt == NULL) {
1190 return cli_bad_descriptor;
1191 }
1192 if (!stmt->prepared) {
1193 sql_scanner scanner(stmt->sql.base());
1194 if (scanner.get() != tkn_insert
1195 || scanner.get() != tkn_into
1196 || scanner.get() != tkn_ident)
1197 {
1198 return cli_bad_statement;
1199 }
1200 int rc = match_columns(scanner.identifier(), stmt);
1201 if (rc != cli_ok) {
1202 return rc;
1203 }
1204 stmt->prepared = true;
1205 }
1206 dbSmallBuffer<byte> buf(stmt->table->appSize);
1207 byte* obj = buf.base();
1208 memset(obj, 0, stmt->table->appSize);
1209 dbFieldDescriptor *first = stmt->table->columns, *fd = first;
1210 do {
1211 if (fd->appType == dbField::tpString) {
1212 *(char_t**)(obj + fd->appOffs) = STRLITERAL("");
1213 }
1214 } while ((fd = fd->next) != first);
1215
1216 char* rec = (char*)buf.base();
1217 int rc = store_columns(rec, stmt, true);
1218 if (rc != cli_ok) {
1219 return rc;
1220 }
1221
1222 dbAnyReference ref;
1223 GB_TRY
1224 if (!stmt->session->db->insertRecord(stmt->table, &ref, rec, batch)) {
1225 stmt->oid = 0;
1226 return cli_not_unique;
1227 }
1228 GB_CATCH
1229 stmt->oid = ref.getOid();
1230 if (oid != NULL) {
1231 *oid = ref.getOid();
1232 }
1233 if (stmt->n_autoincremented_columns > 0) {
1234 for (column_binding* cb = stmt->columns; cb != NULL; cb = cb->next) {
1235 if (cb->var_type == cli_autoincrement) {
1236 *(cli_int4_t*)cb->var_ptr = *(int4*)(rec + cb->field->appOffs);
1237 }
1238 }
1239 }
1240 return cli_ok;
1241 }
1242
1243 int cli_update(int statement)
1244 {
1245 return dbCLI::instance.update(statement);
1246 }
1247
1248 int dbCLI::update(int statement)
1249 {
1250 statement_desc* stmt = statements.get(statement);
1251 if (stmt == NULL) {
1252 return cli_bad_descriptor;
1253 }
1254 if (!stmt->prepared) {
1255 return cli_not_fetched;
1256 }
1257 if (stmt->cursor_type != cli_cursor_for_update) {
1258 return cli_not_update_mode;
1259 }
1260 if (stmt->updated) {
1261 return cli_already_updated;
1262 }
1263 if (stmt->cursor.isEmpty()) {
1264 return cli_not_found;
1265 }
1266 bool succeed;
1267 GB_TRY
1268 if (stmt->record_struct == NULL) {
1269 dbSmallBuffer<byte> buf(stmt->table->appSize);
1270 byte* record = buf.base();
1271 memset(record, 0, stmt->table->appSize);
1272 stmt->cursor.setRecord(record);
1273 stmt->cursor.fetch();
1274
1275 int rc = store_columns((char*)buf.base(), stmt, false);
1276 if (rc != cli_ok) {
1277 stmt->cursor.setRecord(NULL);
1278 return rc;
1279 }
1280 succeed = stmt->cursor.update();
1281 stmt->cursor.setRecord(NULL);
1282 } else {
1283 succeed = stmt->cursor.update();
1284 }
1285 GB_CATCH
1286 if (succeed) {
1287 stmt->updated = true;
1288 return cli_ok;
1289 } else {
1290 return cli_not_unique;
1291 }
1292 }
1293
1294 int cli_freeze(int statement)
1295 {
1296 return dbCLI::instance.freeze(statement);
1297 }
1298
1299 int dbCLI::freeze(int statement)
1300 {
1301 statement_desc* stmt = statements.get(statement);
1302 if (stmt == NULL) {
1303 return cli_bad_descriptor;
1304 }
1305 if (!stmt->prepared) {
1306 return cli_not_fetched;
1307 }
1308 stmt->cursor.freeze();
1309 return cli_ok;
1310 }
1311
1312 int cli_unfreeze(int statement)
1313 {
1314 return dbCLI::instance.unfreeze(statement);
1315 }
1316
1317 int dbCLI::unfreeze(int statement)
1318 {
1319 statement_desc* stmt = statements.get(statement);
1320 if (stmt == NULL) {
1321 return cli_bad_descriptor;
1322 }
1323 if (!stmt->prepared) {
1324 return cli_not_fetched;
1325 }
1326 GB_TRY
1327 stmt->cursor.unfreeze();
1328 GB_CATCH
1329 return cli_ok;
1330 }
1331
1332 int cli_get_first(int statement)
1333 {
1334 return dbCLI::instance.get_first(statement);
1335 }
1336
1337 int dbCLI::get_first(int statement)
1338 {
1339 statement_desc* stmt = statements.get(statement);
1340 if (stmt == NULL) {
1341 return cli_bad_descriptor;
1342 }
1343 if (!stmt->prepared) {
1344 return cli_not_fetched;
1345 }
1346 if (!stmt->cursor.gotoFirst()) {
1347 return cli_not_found;
1348 }
1349 return fetch_columns(stmt);
1350 }
1351
1352 int cli_get_last(int statement)
1353 {
1354 return dbCLI::instance.get_last(statement);
1355 }
1356
1357 int dbCLI::get_last(int statement)
1358 {
1359 statement_desc* stmt = statements.get(statement);
1360 if (stmt == NULL) {
1361 return cli_bad_descriptor;
1362 }
1363 if (!stmt->prepared) {
1364 return cli_not_fetched;
1365 }
1366 if (!stmt->cursor.gotoLast()) {
1367 return cli_not_found;
1368 }
1369 return fetch_columns(stmt);
1370 }
1371
1372 int cli_remove_current(int statement)
1373 {
1374 return dbCLI::instance.remove_current(statement);
1375 }
1376
1377 int dbCLI::remove_current(int statement)
1378 {
1379 statement_desc* stmt = statements.get(statement);
1380 if (stmt == NULL) {
1381 return cli_bad_descriptor;
1382 }
1383 if (!stmt->prepared) {
1384 return cli_not_fetched;
1385 }
1386 if (stmt->cursor_type != cli_cursor_for_update) {
1387 return cli_not_update_mode;
1388 }
1389 if (stmt->cursor.isEmpty()) {
1390 return cli_not_found;
1391 }
1392 GB_TRY
1393 stmt->cursor.remove();
1394 GB_CATCH
1395 return cli_ok;
1396 }
1397
1398 int cli_get_next(int statement)
1399 {
1400 return dbCLI::instance.get_next(statement);
1401 }
1402
1403 int dbCLI::get_next(int statement)
1404 {
1405 statement_desc* stmt = statements.get(statement);
1406 if (stmt == NULL) {
1407 return cli_bad_descriptor;
1408 }
1409 if (!stmt->prepared) {
1410 return cli_not_fetched;
1411 }
1412 if (!((stmt->first_fetch && stmt->cursor.gotoFirst()) ||
1413 (!stmt->first_fetch && stmt->cursor.moveNext())))
1414 {
1415 return cli_not_found;
1416 }
1417 return fetch_columns(stmt);
1418 }
1419
1420 int cli_get_prev(int statement)
1421 {
1422 return dbCLI::instance.get_prev(statement);
1423 }
1424
1425 int dbCLI::get_prev(int statement)
1426 {
1427 statement_desc* stmt = statements.get(statement);
1428 if (stmt == NULL) {
1429 return cli_bad_descriptor;
1430 }
1431 if (!stmt->prepared) {
1432 return cli_not_fetched;
1433 }
1434 if (!((stmt->first_fetch && stmt->cursor.gotoLast()) ||
1435 (!stmt->first_fetch && stmt->cursor.movePrev())))
1436 {
1437 return cli_not_found;
1438 }
1439 return fetch_columns(stmt);
1440 }
1441
1442 int cli_skip(int statement, int n)
1443 {
1444 return dbCLI::instance.skip(statement, n);
1445 }
1446
1447 int dbCLI::skip(int statement, int n)
1448 {
1449 statement_desc* stmt = statements.get(statement);
1450 if (stmt == NULL) {
1451 return cli_bad_descriptor;
1452 }
1453 if (!stmt->prepared) {
1454 return cli_not_fetched;
1455 }
1456 if ((n > 0 && !(((stmt->first_fetch && stmt->cursor.gotoFirst() && stmt->cursor.skip(n-1))
1457 || (!stmt->first_fetch && stmt->cursor.skip(n)))))
1458 || (n < 0 && !(((stmt->first_fetch && stmt->cursor.gotoLast() && stmt->cursor.skip(n+1))
1459 || (!stmt->first_fetch && stmt->cursor.skip(n))))))
1460 {
1461 return cli_not_found;
1462 }
1463 return fetch_columns(stmt);
1464 }
1465
1466 int cli_seek(int statement, cli_oid_t oid)
1467 {
1468 return dbCLI::instance.seek(statement, oid);
1469 }
1470
1471 int dbCLI::seek(int statement, cli_oid_t oid)
1472 {
1473 statement_desc* stmt = statements.get(statement);
1474 if (stmt == NULL) {
1475 return cli_bad_descriptor;
1476 }
1477 if (!stmt->prepared) {
1478 return cli_not_fetched;
1479 }
1480 int pos = stmt->cursor.seek(oid);
1481 if (pos < 0) {
1482 return cli_not_found;
1483 }
1484 int rc = fetch_columns(stmt);
1485 if (rc == cli_ok) {
1486 return pos;
1487 } else {
1488 return rc;
1489 }
1490 }
1491
1492 cli_oid_t cli_get_oid(int statement)
1493 {
1494 return dbCLI::instance.get_current_oid(statement);
1495 }
1496
1497 cli_oid_t dbCLI::get_current_oid(int statement)
1498 {
1499 statement_desc* stmt = statements.get(statement);
1500 if (stmt == NULL) {
1501 return (cli_oid_t)cli_bad_descriptor;
1502 }
1503 return stmt->cursor.currId;
1504 }
1505
1506
1507 int cli_close_cursor(int statement)
1508 {
1509 return dbCLI::instance.close_cursor(statement);
1510 }
1511
1512 int dbCLI::close_cursor(int statement)
1513 {
1514 statement_desc* stmt = statements.get(statement);
1515 if (stmt == NULL) {
1516 return cli_bad_descriptor;
1517 }
1518 if (stmt->cursor.db != NULL) {
1519 stmt->cursor.reset();
1520 stmt->cursor.deallocateBitmap();
1521 }
1522 return cli_ok;
1523 }
1524
1525 int cli_free(int statement)
1526 {
1527 return dbCLI::instance.free_statement(statement);
1528 }
1529
1530 int dbCLI::free_statement(int statement)
1531 {
1532 statement_desc* stmt = statements.get(statement);
1533 if (stmt == NULL) {
1534 return cli_bad_descriptor;
1535 }
1536 return free_statement(stmt);
1537 }
1538
1539 int dbCLI::free_statement(statement_desc* stmt)
1540 {
1541 {
1542 dbCriticalSection cs(stmt->session->mutex);
1543 statement_desc *sp, **spp = &stmt->session->stmts;
1544 while ((sp = *spp) != stmt) {
1545 if (sp == NULL) {
1546 return cli_bad_descriptor;
1547 }
1548 spp = &sp->next;
1549 }
1550 *spp = stmt->next;
1551 }
1552 return release_statement(stmt);
1553 }
1554
1555 int dbCLI::release_statement(statement_desc* stmt)
1556 {
1557 column_binding *cb, *next_cb;
1558 for (cb = stmt->columns; cb != NULL; cb = next_cb) {
1559 next_cb = cb->next;
1560 delete[] cb->name;
1561 column_allocator.free(cb);
1562 }
1563 parameter_binding *pb, *next_pb;
1564 for (pb = stmt->params; pb != NULL; pb = next_pb) {
1565 next_pb = pb->next;
1566 delete[] pb->name;
1567 parameter_allocator.free(pb);
1568 }
1569 if (stmt->cursor.db != NULL) {
1570 stmt->cursor.reset();
1571 stmt->cursor.deallocateBitmap();
1572 }
1573 statements.free(stmt);
1574 return cli_ok;
1575 }
1576
1577
1578 int cli_commit(int session)
1579 {
1580 return dbCLI::instance.commit(session);
1581 }
1582
1583 int cli_exec_batch(int session)
1584 {
1585 return dbCLI::instance.exec_batch(session);
1586 }
1587
1588 int dbCLI::exec_batch(int session)
1589 {
1590 session_desc* s = sessions.get(session);
1591 if (s == NULL) {
1592 return cli_bad_descriptor;
1593 }
1594 GB_TRY
1595 s->db->executeBatch();
1596 GB_CATCH
1597 return cli_ok;
1598 }
1599
1600 int dbCLI::commit(int session)
1601 {
1602 session_desc* s = sessions.get(session);
1603 if (s == NULL) {
1604 return cli_bad_descriptor;
1605 }
1606 while (s->dropped_tables != NULL) {
1607 dbTableDescriptor* next = s->dropped_tables->nextDbTable;
1608 delete s->dropped_tables;
1609 s->dropped_tables = next;
1610 }
1611 GB_TRY
1612 s->db->commit();
1613 GB_CATCH
1614 s->existed_tables = NULL;
1615 return cli_ok;
1616 }
1617
1618 int cli_precommit(int session)
1619 {
1620 return dbCLI::instance.precommit(session);
1621 }
1622
1623 int dbCLI::precommit(int session)
1624 {
1625 session_desc* s = sessions.get(session);
1626 if (s == NULL) {
1627 return cli_bad_descriptor;
1628 }
1629 GB_TRY
1630 s->db->precommit();
1631 GB_CATCH
1632 return cli_ok;
1633 }
1634
1635 int cli_abort(int session)
1636 {
1637 return dbCLI::instance.abort(session);
1638 }
1639
1640 int dbCLI::abort(int session)
1641 {
1642 session_desc* s = sessions.get(session);
1643 if (s == NULL) {
1644 return cli_bad_descriptor;
1645 }
1646 dbDatabase* db = s->db;
1647 while (s->dropped_tables != NULL) {
1648 dbTableDescriptor* next = s->dropped_tables->nextDbTable;
1649 db->linkTable(s->dropped_tables, s->dropped_tables->tableId);
1650 s->dropped_tables = next;
1651 }
1652 if (s->existed_tables != NULL) {
1653 while (db->tables != s->existed_tables) {
1654 dbTableDescriptor* table = db->tables;
1655 db->unlinkTable(table);
1656 delete table;
1657 }
1658 s->existed_tables = NULL;
1659 }
1660 GB_TRY
1661 s->db->rollback();
1662 GB_CATCH
1663 return cli_ok;
1664 }
1665
1666
1667 int cli_remove(int statement)
1668 {
1669 return dbCLI::instance.remove(statement);
1670 }
1671
1672 int dbCLI::remove(int statement)
1673 {
1674 statement_desc* stmt = statements.get(statement);
1675 if (stmt == NULL || !stmt->prepared) {
1676 return cli_bad_descriptor;
1677 }
1678 if (stmt->cursor_type != cli_cursor_for_update) {
1679 return cli_not_update_mode;
1680 }
1681 if (stmt->cursor.isEmpty()) {
1682 return cli_not_found;
1683 }
1684 GB_TRY
1685 stmt->cursor.removeAllSelected();
1686 GB_CATCH
1687 return cli_ok;
1688 }
1689
1690 int cli_describe(int session, char_t const* table, cli_field_descriptor** fields)
1691 {
1692 return dbCLI::instance.describe(session, table, fields);
1693 }
1694
1695 int dbCLI::describe(int session, char_t const* table, cli_field_descriptor** fields)
1696 {
1697 session_desc* s = sessions.get(session);
1698 if (s == NULL) {
1699 return cli_bad_descriptor;
1700 }
1701 dbDatabase* db = s->db;
1702 dbTableDescriptor* desc = db->findTableByName(table);
1703 if (desc == NULL) {
1704 return cli_table_not_found;
1705 } else {
1706 int nColumns = (int)desc->nColumns;
1707 cli_field_descriptor* fp =
1708 (cli_field_descriptor*)malloc(nColumns*sizeof(cli_field_descriptor));
1709 dbFieldDescriptor* fd = desc->columns;
1710 *fields = fp;
1711 for (int i = 0; i < nColumns; i++, fp++) {
1712 fp->type = (cli_var_type)map_type(fd);
1713 fp->name = fd->name;
1714 fp->refTableName = (fd->type == dbField::tpArray) ? fd->components->refTableName : fd->refTableName;
1715 fp->inverseRefFieldName = fd->inverseRefName;
1716 fp->flags = fd->indexType;
1717 if (fd->bTree != 0) {
1718 fp->flags |= cli_indexed;
1719 if (fp->type != cli_rectangle) {
1720 dbGetTie tie;
1721 dbBtree* tree = (dbBtree*)db->getRow(tie, fd->bTree);
1722 if (tree->isCaseInsensitive()) {
1723 fp->flags |= cli_case_insensitive;
1724 }
1725 if (tree->isThick()) {
1726 fp->flags |= cli_optimize_duplicates;
1727 }
1728 if (tree->isUnique()) {
1729 fp->flags |= cli_unique;
1730 }
1731 }
1732 }
1733 if (fd->hashTable != 0) {
1734 fp->flags |= cli_hashed;
1735 }
1736 fd = fd->next;
1737 }
1738 return nColumns;
1739 }
1740 }
1741
1742
1743 int cli_describe_layout(int session, char_t const* table, cli_field_layout** fields, int* rec_size)
1744 {
1745 return dbCLI::instance.describe_layout(session, table, fields, rec_size);
1746 }
1747
1748 int dbCLI::describe_layout(int session, char_t const* table, cli_field_layout** fields, int* rec_size)
1749 {
1750 session_desc* s = sessions.get(session);
1751 if (s == NULL) {
1752 return cli_bad_descriptor;
1753 }
1754 dbDatabase* db = s->db;
1755 dbTableDescriptor* desc = db->findTableByName(table);
1756 if (desc == NULL) {
1757 return cli_table_not_found;
1758 } else {
1759 int nColumns = (int)desc->nColumns;
1760 cli_field_layout* fp =
1761 (cli_field_layout*)malloc(nColumns*sizeof(cli_field_layout));
1762 dbFieldDescriptor* fd = desc->columns;
1763 *fields = fp;
1764 *rec_size = (int)desc->appSize;
1765 for (int i = 0; i < nColumns; i++, fp++) {
1766 fp->desc.type = (cli_var_type)map_type(fd);
1767 fp->desc.name = fd->name;
1768 fp->desc.refTableName = (fd->type == dbField::tpArray) ? fd->components->refTableName : fd->refTableName;
1769 fp->desc.inverseRefFieldName = fd->inverseRefName;
1770 fp->desc.flags = fd->indexType;
1771 if (fd->bTree != 0) {
1772 fp->desc.flags |= cli_indexed;
1773 if (fp->desc.type != cli_rectangle) {
1774 dbGetTie tie;
1775 dbBtree* tree = (dbBtree*)db->getRow(tie, fd->bTree);
1776 if (tree->isCaseInsensitive()) {
1777 fp->desc.flags |= cli_case_insensitive;
1778 }
1779 if (tree->isThick()) {
1780 fp->desc.flags |= cli_optimize_duplicates;
1781 }
1782 if (tree->isUnique()) {
1783 fp->desc.flags |= cli_unique;
1784 }
1785 }
1786 }
1787 if (fd->hashTable != 0) {
1788 fp->desc.flags |= cli_hashed;
1789 }
1790 fp->offs = fd->appOffs;
1791 fp->size = (int)fd->appSize;
1792 fd = fd->next;
1793 }
1794 return nColumns;
1795 }
1796 }
1797
1798
1799 int cli_show_tables(int session, cli_table_descriptor** tables)
1800 {
1801 return dbCLI::instance.show_tables(session, tables);
1802 }
1803
1804 int dbCLI::show_tables(int session, cli_table_descriptor** tables)
1805 {
1806 session_desc* s = sessions.get(session);
1807 if (s == NULL) {
1808 return cli_bad_descriptor;
1809 }
1810 dbTableDescriptor* desc;
1811 int nTables = 0;
1812 for (desc = s->db->tables; desc != NULL; desc = desc->nextDbTable) {
1813 if (STRCMP(desc->name, STRLITERAL("Metatable"))) {
1814 nTables += 1;
1815 }
1816 }
1817 if (nTables != 0) {
1818 cli_table_descriptor* td = (cli_table_descriptor*)malloc(nTables*sizeof(cli_table_descriptor));
1819 *tables = td;
1820 for (desc = s->db->tables; desc != NULL; desc = desc->nextDbTable) {
1821 if (STRCMP(desc->name, STRLITERAL("Metatable"))) {
1822 td->name = desc->name;
1823 td += 1;
1824 }
1825 }
1826 } else {
1827 *tables = NULL;
1828 }
1829 return nTables;
1830 }
1831
1832 int cli_get_wrapping_rectangle(int session, char_t const* table, char_t const* field, cli_rectangle_t* rect)
1833 {
1834 return dbCLI::instance.get_wrapping_rectangle(session, table, field, rect);
1835 }
1836
1837 int dbCLI::get_wrapping_rectangle(int session, char_t const* table, char_t const* field, cli_rectangle_t* rect)
1838 {
1839 session_desc* s = sessions.get(session);
1840 if (s == NULL) {
1841 return cli_bad_descriptor;
1842 }
1843 dbDatabase* db = s->db;
1844 dbTableDescriptor* desc = db->findTableByName(table);
1845 if (desc == NULL) {
1846 return cli_table_not_found;
1847 } else {
1848 dbFieldDescriptor* fd = desc->find(field);
1849 if (fd == NULL || fd->type != dbField::tpRectangle || fd->bTree == 0) {
1850 return cli_column_not_found;
1851 }
1852 dbRtree::cover(db, fd->bTree, *(rectangle*)rect);
1853 return cli_ok;
1854 }
1855 }
1856
1857 #define MAX_QUERY_IDENTIFIER_LENGTH 256
1858
1859 int sql_scanner::get()
1860 {
1861 char_t buf[MAX_QUERY_IDENTIFIER_LENGTH];
1862 int i = 0, ch;
1863
1864 do {
1865 ch = *p++;
1866 if (ch == '\0') {
1867 return tkn_eof;
1868 }
1869 } while (ch > 0 && ch <= 32);
1870
1871 if (ch == '*') {
1872 return tkn_all;
1873 } else if ((ch >= '0' && ch <= '9') || ch == '+' || ch == '-') {
1874 int const_type = tkn_iconst;
1875 while (true) {
1876 ch = *p++;
1877 if (ch == '.' || ch == 'e' || ch == 'E') {
1878 const_type = tkn_fconst;
1879 } else if (!((ch >= '0' && ch <= '9') || ch == '+' || ch == '-')) {
1880 break;
1881 }
1882 }
1883 return const_type;
1884 } else if (ISALNUM(ch) || ch == '$' || ch == '_') {
1885 do {
1886 buf[i++] = ch;
1887 if (i == MAX_QUERY_IDENTIFIER_LENGTH) {
1888 // Identifier too long
1889 return tkn_error;
1890 }
1891 ch = *p++;
1892 } while (ch != T_EOF && (ISALNUM(ch) || ch == '$' || ch == '_'));
1893 p -= 1;
1894 buf[i] = '\0';
1895 ident = buf;
1896 return dbSymbolTable::add(ident, tkn_ident);
1897 } else {
1898 // Invalid symbol
1899 return tkn_error;
1900 }
1901 }
1902
1903
1904 int cli_create_table(int session, char_t const* tableName, int nColumns,
1905 cli_field_descriptor* columns)
1906 {
1907 return dbCLI::instance.create_table(session, tableName, nColumns, columns);
1908 }
1909
1910 int cli_alter_table(int session, char_t const* tableName, int nColumns,
1911 cli_field_descriptor* columns)
1912 {
1913 return dbCLI::instance.alter_table(session, tableName, nColumns, columns);
1914 }
1915
1916
1917 int dbCLI::create_table(int session, char_t const* tableName, int nColumns,
1918 cli_field_descriptor* columns)
1919 {
1920 session_desc* s = sessions.get(session);
1921 if (s == NULL) {
1922 return cli_bad_descriptor;
1923 }
1924 GB_TRY
1925 s->db->beginTransaction(dbUpdateLock);
1926 if (s->existed_tables == NULL) {
1927 s->existed_tables = s->db->tables;
1928 }
1929 return create_table(s->db, tableName, nColumns, columns);
1930 GB_CATCH
1931 }
1932
1933 int dbCLI::alter_table(int session, char_t const* tableName, int nColumns,
1934 cli_field_descriptor* columns)
1935 {
1936 session_desc* s = sessions.get(session);
1937 if (s == NULL) {
1938 return cli_bad_descriptor;
1939 }
1940 GB_TRY
1941 s->db->beginTransaction(dbUpdateLock);
1942 return alter_table(s->db, tableName, nColumns, columns);
1943 GB_CATCH
1944 }
1945
1946 int dbCLI::calculate_varying_length(char_t const* tableName, int& nFields, cli_field_descriptor* columns)
1947 {
1948 size_t varyingLength = (STRLEN(tableName) + 1)*sizeof(char_t);
1949 for (int i = 0, n = nFields; i < n; i++) {
1950 int type = columns[i].type;
1951 varyingLength += (STRLEN(columns[i].name) + 3)*sizeof(char_t);
1952 if (type == cli_oid || type == cli_array_of_oid) {
1953 varyingLength += STRLEN(columns[i].refTableName)*sizeof(char_t);
1954 if (columns[i].inverseRefFieldName != NULL) {
1955 varyingLength += STRLEN(columns[i].inverseRefFieldName)*sizeof(char_t);
1956 }
1957 }
1958 switch (type) {
1959 case cli_oid:
1960 case cli_bool:
1961 case cli_int1:
1962 case cli_int2:
1963 case cli_int4:
1964 case cli_autoincrement:
1965 case cli_int8:
1966 case cli_real4:
1967 case cli_real8:
1968 case cli_asciiz:
1969 case cli_pasciiz:
1970 case cli_datetime:
1971 case cli_rectangle:
1972 break;
1973 case cli_array_of_oid:
1974 case cli_array_of_bool:
1975 case cli_array_of_int1:
1976 case cli_array_of_int2:
1977 case cli_array_of_int4:
1978 case cli_array_of_int8:
1979 case cli_array_of_real4:
1980 case cli_array_of_real8:
1981 case cli_array_of_string:
1982 varyingLength += (STRLEN(columns[i].name) + 2 + 3)*sizeof(char_t);
1983 nFields += 1;
1984 break;
1985 case cli_decimal:
1986 case cli_cstring:
1987 case cli_array_of_decimal:
1988 case cli_any:
1989 case cli_unknown:
1990 return cli_unsupported_type;
1991 }
1992 }
1993 return (int)varyingLength;
1994 }
1995
1996 dbTableDescriptor* dbCLI::create_table_descriptor(dbDatabase* db,
1997 dbTable* table,
1998 char_t const* tableName,
1999 int nFields,
2000 int nColumns,
2001 cli_field_descriptor* columns)
2002 {
2003 int offs = sizeof(dbTable) + sizeof(dbField)*nFields;
2004 table->name.offs = offs;
2005 table->name.size = (nat4)STRLEN(tableName)+1;
2006 STRCPY((char_t*)((byte*)table + offs), tableName);
2007 offs += table->name.size*sizeof(char_t);
2008 size_t size = sizeof(dbRecord);
2009 table->fields.offs = sizeof(dbTable);
2010 dbField* field = (dbField*)((char*)table + table->fields.offs);
2011 offs -= sizeof(dbTable);
2012
2013 for (int i = 0; i < nColumns; i++, field += 1, offs -= sizeof(dbField)) {
2014 field->name.offs = offs;
2015 field->name.size = (nat4)STRLEN(columns[i].name) + 1;
2016 STRCPY((char_t*)((char*)field + offs), columns[i].name);
2017 offs += field->name.size*sizeof(char_t);
2018 field->tableName.offs = offs;
2019 int type = columns[i].type;
2020
2021 if (type == cli_oid || type == cli_array_of_oid) {
2022 if (type == cli_oid) {
2023 field->tableName.size = (nat4)STRLEN(columns[i].refTableName) + 1;
2024 STRCPY((char_t*)((byte*)field + offs), columns[i].refTableName);
2025 offs += field->tableName.size*sizeof(char_t);
2026 } else {
2027 field->tableName.size = 1;
2028 *(char_t*)((char*)field + offs) = '\0';
2029 offs += sizeof(char_t);
2030 }
2031 field->inverse.offs = offs;
2032 if (columns[i].inverseRefFieldName != NULL) {
2033 field->inverse.size = (nat4)STRLEN(columns[i].inverseRefFieldName) + 1;
2034 STRCPY((char_t*)((byte*)field + offs), columns[i].inverseRefFieldName);
2035 offs += field->inverse.size*sizeof(char_t);
2036 } else {
2037 field->inverse.size = 1;
2038 *(char_t*)((char*)field + offs) = '\0';
2039 offs += sizeof(char_t);
2040 }
2041 } else {
2042 field->tableName.size = 1;
2043 *(char_t*)((char*)field + offs) = '\0';
2044 offs += sizeof(char_t);
2045 field->inverse.size = 1;
2046 field->inverse.offs = offs;
2047 *(char_t*)((char*)field + offs) = '\0';
2048 offs += sizeof(char_t);
2049 }
2050 field->bTree = field->hashTable = 0;
2051 field->flags = columns[i].flags;
2052
2053 switch (type) {
2054 case cli_oid:
2055 field->type = dbField::tpReference;
2056 field->size = sizeof(oid_t);
2057 break;
2058 case cli_bool:
2059 field->type = dbField::tpBool;
2060 field->size = sizeof(bool);
2061 break;
2062 case cli_int1:
2063 field->type = dbField::tpInt1;
2064 field->size = sizeof(int1);
2065 break;
2066 case cli_int2:
2067 field->type = dbField::tpInt2;
2068 field->size = sizeof(int2);
2069 break;
2070 case cli_autoincrement:
2071 field->flags |= AUTOINCREMENT;
2072 // no break
2073 case cli_int4:
2074 field->type = dbField::tpInt4;
2075 field->size = sizeof(int4);
2076 break;
2077 case cli_int8:
2078 field->type = dbField::tpInt8;
2079 field->size = sizeof(db_int8);
2080 break;
2081 case cli_real4:
2082 field->type = dbField::tpReal4;
2083 field->size = sizeof(real4);
2084 break;
2085 case cli_real8:
2086 field->type = dbField::tpReal8;
2087 field->size = sizeof(real8);
2088 break;
2089 case cli_datetime:
2090 field->type = (sizeof(cli_time_t) == 4) ? dbField::tpInt4 : dbField::tpInt8;
2091 field->size = sizeof(cli_time_t);
2092 field->flags |= DB_TIMESTAMP;
2093 break;
2094 case cli_rectangle:
2095 field->type = dbField::tpRectangle;
2096 field->size = sizeof(cli_rectangle_t);
2097 if (db != NULL && (columns[i].flags & (cli_hashed|cli_indexed))) {
2098 field->bTree = dbRtree::allocate(db);
2099 }
2100 field->offset = (int4)DOALIGN(size, sizeof(cli_coord_t));
2101 size = field->offset + sizeof(cli_rectangle_t);
2102 continue;
2103 case cli_asciiz:
2104 case cli_pasciiz:
2105 case cli_cstring:
2106 field->type = dbField::tpString;
2107 field->size = sizeof(dbVarying);
2108 field->offset = (int4)DOALIGN(size, sizeof(int4));
2109 size = field->offset + sizeof(dbVarying);
2110 if (columns[i].flags & (cli_hashed|cli_indexed)) {
2111 int flags = 0;
2112 if (columns[i].flags & cli_case_insensitive) {
2113 flags |= dbBtree::FLAGS_CASE_INSENSITIVE;
2114 }
2115 if (columns[i].flags & cli_optimize_duplicates) {
2116 flags |= dbBtree::FLAGS_THICK;
2117 }
2118 if (columns[i].flags & cli_unique) {
2119 flags |= dbBtree::FLAGS_UNIQUE;
2120 }
2121 if (db != NULL) {
2122 field->bTree = dbBtree::allocate(db, dbField::tpString, 0, flags);
2123 }
2124 }
2125 continue;
2126 case cli_array_of_oid:
2127 case cli_array_of_bool:
2128 case cli_array_of_int1:
2129 case cli_array_of_int2:
2130 case cli_array_of_int4:
2131 case cli_array_of_int8:
2132 case cli_array_of_real4:
2133 case cli_array_of_real8:
2134 case cli_array_of_string:
2135 field->type = dbField::tpArray;
2136 field->size = sizeof(dbVarying);
2137 field->offset = (int4)DOALIGN(size, sizeof(int4));
2138 size = field->offset + sizeof(dbVarying);
2139 field += 1;
2140 offs -= sizeof(dbField);
2141 field->name.offs = offs;
2142 field->name.size = (nat4)STRLEN(columns[i].name) + 3;
2143 SPRINTF(SPRINTF_BUFFER((char_t*)((char*)field + offs)), STRLITERAL("%s[]"), columns[i].name);
2144 offs += field->name.size*sizeof(char_t);
2145 field->tableName.offs = offs;
2146 if (type == cli_array_of_oid) {
2147 field->tableName.size = (nat4)STRLEN(columns[i].refTableName) + 1;
2148 STRCPY((char_t*)((char*)field + offs), columns[i].refTableName);
2149 offs += field->tableName.size*sizeof(char_t);
2150 } else {
2151 field->tableName.size = 1;
2152 *(char_t*)((char*)field + offs) = '\0';
2153 offs += sizeof(char_t);
2154 }
2155 field->inverse.offs = offs;
2156 field->inverse.size = 1;
2157 *(char_t*)((char*)field + offs) = '\0';
2158 offs += sizeof(char_t);
2159 field->offset = 0;
2160 field->hashTable = field->bTree = 0;
2161 switch (type) {
2162 case cli_array_of_oid:
2163 field->type = dbField::tpReference;
2164 field->size = sizeof(oid_t);
2165 break;
2166 case cli_array_of_bool:
2167 field->type = dbField::tpBool;
2168 field->size = sizeof(bool);
2169 break;
2170 case cli_array_of_int1:
2171 field->type = dbField::tpInt1;
2172 field->size = sizeof(int1);
2173 break;
2174 case cli_array_of_int2:
2175 field->type = dbField::tpInt2;
2176 field->size = sizeof(int2);
2177 break;
2178 case cli_array_of_int4:
2179 field->type = dbField::tpInt4;
2180 field->size = sizeof(int4);
2181 break;
2182 case cli_array_of_int8:
2183 field->type = dbField::tpInt8;
2184 field->size = sizeof(db_int8);
2185 break;
2186 case cli_array_of_real4:
2187 field->type = dbField::tpReal4;
2188 field->size = sizeof(real4);
2189 break;
2190 case cli_array_of_real8:
2191 field->type = dbField::tpReal8;
2192 field->size = sizeof(real8);
2193 break;
2194 case cli_array_of_string:
2195 field->type = dbField::tpString;
2196 field->size = sizeof(dbVarying);
2197 break;
2198 }
2199 continue;
2200 default:
2201 return NULL;
2202 }
2203 if (columns[i].flags & (cli_hashed|cli_indexed)) {
2204 int flags = 0;
2205 if (columns[i].flags & cli_case_insensitive) {
2206 flags |= dbBtree::FLAGS_CASE_INSENSITIVE;
2207 }
2208 if (columns[i].flags & cli_optimize_duplicates) {
2209 flags |= dbBtree::FLAGS_THICK;
2210 }
2211 if (columns[i].flags & cli_unique) {
2212 flags |= dbBtree::FLAGS_UNIQUE;
2213 }
2214 if (db != NULL) {
2215 field->bTree = dbBtree::allocate(db, field->type, field->size, flags);
2216 }
2217 }
2218 field->offset = (int4)DOALIGN(size, field->size);
2219 size = field->offset + field->size;
2220 }
2221 table->fields.size = nFields;
2222 table->fixedSize = (nat4)size;
2223 table->nRows = 0;
2224 table->nColumns = nColumns;
2225 table->firstRow = 0;
2226 table->lastRow = 0;
2227
2228 return new dbTableDescriptor(table);
2229 }
2230
2231 int dbCLI::create_table(dbDatabase* db, char_t const* tableName, int nColumns,
2232 cli_field_descriptor* columns)
2233 {
2234 db->modified = true;
2235 if (db->findTableByName(tableName) != NULL) {
2236 return cli_table_already_exists;
2237 }
2238 int nFields = nColumns;
2239 int varyingLength = calculate_varying_length(tableName, nFields, columns);
2240
2241 db->beginTransaction(dbExclusiveLock);
2242 oid_t oid = db->allocateRow(dbMetaTableId,
2243 sizeof(dbTable) + sizeof(dbField)*nFields + varyingLength);
2244 dbPutTie tie;
2245 dbTable* table = (dbTable*)db->putRow(tie, oid);
2246
2247 dbTableDescriptor* desc = create_table_descriptor(db, table, tableName, nFields, nColumns, columns);
2248 if (desc == NULL) {
2249 return cli_unsupported_type;
2250 }
2251 db->linkTable(desc, oid);
2252 if (!db->completeDescriptorsInitialization()) {
2253 return cli_table_not_found;
2254 }
2255 return cli_ok;
2256 }
2257
2258
2259 int dbCLI::alter_table(dbDatabase* db, char_t const* tableName, int nColumns,
2260 cli_field_descriptor* columns)
2261 {
2262 dbTableDescriptor* oldDesc = db->findTableByName(tableName);
2263 if (oldDesc == NULL) {
2264 return cli_table_not_found;
2265 }
2266 int nFields = nColumns;
2267 int varyingLength = calculate_varying_length(tableName, nFields, columns);
2268
2269 dbTable* newTable = (dbTable*)new char[sizeof(dbTable) + sizeof(dbField)*nFields + varyingLength];
2270 dbTableDescriptor* newDesc = create_table_descriptor(NULL, newTable, tableName, nFields, nColumns, columns);
2271 delete[] (char*)newTable;
2272 if (newDesc == NULL) {
2273 return cli_unsupported_type;
2274 }
2275 GB_TRY
2276 db->beginTransaction(dbExclusiveLock);
2277 dbGetTie tie;
2278 oid_t tableId = oldDesc->tableId;
2279 dbTable* oldTable = (dbTable*)db->getRow(tie, tableId);
2280 if (!newDesc->equal(oldTable)) {
2281 bool confirmDeleteColumns = db->confirmDeleteColumns;
2282 db->confirmDeleteColumns = true;
2283 db->modified = true;
2284 db->schemeVersion += 1;
2285 db->unlinkTable(oldDesc);
2286 if (oldTable->nRows == 0) {
2287 db->updateTableDescriptor(newDesc, tableId, oldTable);
2288 } else {
2289 db->reformatTable(tableId, newDesc);
2290 }
2291 delete oldDesc;
2292 db->confirmDeleteColumns = confirmDeleteColumns;
2293 db->addIndices(newDesc);
2294 if (!db->completeDescriptorsInitialization()) {
2295 return cli_table_not_found;
2296 }
2297 } else {
2298 delete newDesc;
2299 }
2300 GB_CATCH
2301 return cli_ok;
2302 }
2303
2304 int cli_drop_table(int session, char_t const* tableName)
2305 {
2306 return dbCLI::instance.drop_table(session, tableName);
2307 }
2308
2309
2310 int dbCLI::drop_table(int session, char_t const* tableName)
2311 {
2312 session_desc* s = sessions.get(session);
2313 if (s == NULL) {
2314 return cli_bad_descriptor;
2315 }
2316 dbDatabase* db = s->db;
2317 GB_TRY
2318 db->beginTransaction(dbUpdateLock);
2319 dbTableDescriptor* desc = db->findTableByName(tableName);
2320 if (desc == NULL) {
2321 return cli_table_not_found;
2322 }
2323 db->dropTable(desc);
2324 if (desc == s->existed_tables) {
2325 s->existed_tables = desc->nextDbTable;
2326 }
2327 db->unlinkTable(desc);
2328 desc->nextDbTable = s->dropped_tables;
2329 s->dropped_tables = desc;
2330 GB_CATCH
2331 return cli_ok;
2332 }
2333
2334 int cli_alter_index(int session, char_t const* tableName, char_t const* fieldName, int newFlags)
2335 {
2336 return dbCLI::instance.alter_index(session, tableName, fieldName, newFlags);
2337 }
2338
2339 int dbCLI::alter_index(int session, char_t const* tableName, char_t const* fieldName, int newFlags)
2340 {
2341 session_desc* s = sessions.get(session);
2342 if (s == NULL) {
2343 return cli_bad_descriptor;
2344 }
2345 return alter_index(s->db, tableName, fieldName, newFlags);
2346 }
2347
2348 int dbCLI::alter_index(dbDatabase* db, char_t const* tableName, char_t const* fieldName, int newFlags)
2349 {
2350 GB_TRY
2351 db->beginTransaction(dbUpdateLock);
2352 dbTableDescriptor* desc = db->findTableByName(tableName);
2353 if (desc == NULL) {
2354 return cli_table_not_found;
2355 }
2356 dbFieldDescriptor* fd = desc->find(fieldName);
2357 if (fd == NULL) {
2358 return cli_column_not_found;
2359 }
2360 if (fd->bTree != 0 && (newFlags & (cli_indexed|cli_hashed)) == 0) {
2361 db->dropIndex(fd);
2362 fd->indexType &= ~(INDEXED|OPTIMIZE_DUPLICATES|CASE_INSENSITIVE|UNIQUE);
2363 } else if (fd->bTree == 0 && (newFlags & (cli_indexed|cli_hashed)) != 0) {
2364 fd->indexType |= newFlags & (cli_indexed|cli_hashed|cli_unique|cli_optimize_duplicates|cli_case_insensitive);
2365 db->createIndex(fd);
2366 }
2367 GB_CATCH
2368 return cli_ok;
2369 }
2370
2371 cli_error_handler cli_set_error_handler(int session, cli_error_handler new_handler, void* context)
2372 {
2373 return dbCLI::instance.set_error_handler(session, new_handler, context);
2374 }
2375
2376 cli_error_handler dbCLI::set_error_handler(int session, cli_error_handler new_handler, void* context)
2377 {
2378 session_desc* s = sessions.get(session);
2379 if (s == NULL) {
2380 return NULL;
2381 }
2382 return (cli_error_handler)s->db->setErrorHandler(dbDatabase::dbErrorHandler(new_handler), context);
2383 }
2384
2385
2386
2387 int cli_attach(int session)
2388 {
2389 return dbCLI::instance.attach(session);
2390 }
2391
2392 int dbCLI::attach(int session)
2393 {
2394 session_desc* s = sessions.get(session);
2395 if (s == NULL) {
2396 return cli_bad_descriptor;
2397 }
2398 GB_TRY
2399 s->db->attach();
2400 GB_CATCH
2401 return cli_ok;
2402 }
2403
2404 int cli_detach(int session, int detach_mode)
2405 {
2406 return dbCLI::instance.detach(session, detach_mode);
2407 }
2408
2409 int dbCLI::detach(int session, int detach_mode)
2410 {
2411 session_desc* s = sessions.get(session);
2412 if (s == NULL) {
2413 return cli_bad_descriptor;
2414 }
2415 GB_TRY
2416 s->db->detach(detach_mode);
2417 GB_CATCH
2418 return cli_ok;
2419 }
2420
2421 void cli_free_memory(int, void* ptr)
2422 {
2423 free(ptr);
2424 }
2425
2426 void cli_set_trace_function(cli_trace_function_t func)
2427 {
2428 dbTraceFunction = func;
2429 }
2430
2431
2432 int cli_lock(int session)
2433 {
2434 return dbCLI::instance.lock(session);
2435 }
2436
2437 int dbCLI::lock(int session)
2438 {
2439 session_desc* s = sessions.get(session);
2440 if (s == NULL) {
2441 return cli_bad_descriptor;
2442 }
2443 GB_TRY
2444 s->db->lock();
2445 GB_CATCH
2446 return cli_ok;
2447 }
2448
2449 int cli_prepare_query(int session, char_t const* query)
2450 {
2451 return dbCLI::instance.prepare_query(session, query);
2452 }
2453
2454 int dbCLI::prepare_query(int session, char_t const* query)
2455 {
2456 char_t *p, *q;
2457 int tkn;
2458 session_desc* s = sessions.get(session);
2459 if (s == NULL) {
2460 return cli_bad_descriptor;
2461 }
2462 statement_desc* stmt = statements.allocate();
2463 stmt->columns = NULL;
2464 stmt->params = NULL;
2465 stmt->session = s;
2466 stmt->cursor_type = cli_cursor_view_only;
2467 stmt->first_fetch = true;
2468 stmt->prepared = false;
2469 stmt->n_params = 0;
2470 stmt->n_columns = 0;
2471 stmt->n_autoincremented_columns = 0;
2472 stmt->oid = 0;
2473 stmt->updated = false;
2474 stmt->query.reset();
2475
2476 stmt->sql.put(STRLEN(query)+1);
2477 p = stmt->sql.base();
2478 STRCPY(p, query);
2479
2480 sql_scanner scanner(p);
2481 if (scanner.get() != tkn_select) {
2482 statements.free(stmt);
2483 return cli_bad_statement;
2484 }
2485 if ((tkn = scanner.get()) == tkn_all) {
2486 tkn = scanner.get();
2487 }
2488 if (tkn != tkn_from || scanner.get() != tkn_ident) {
2489 statements.free(stmt);
2490 return cli_bad_statement;
2491 }
2492 stmt->table = s->db->findTable(scanner.identifier());
2493 if (stmt->table == NULL) {
2494 statements.free(stmt);
2495 return cli_table_not_found;
2496 }
2497
2498 p = scanner.current_position();
2499 q = p;
2500 size_t offs = 0;
2501
2502 while (*p != '\0') {
2503 if (*p == '\'') {
2504 do {
2505 do {
2506 p += 1;
2507 } while (*p != '\0' && *p != '\'');
2508 if (*p == '\0') {
2509 statements.free(stmt);
2510 return cli_bad_statement;
2511 }
2512 } while (*++p == '\'');
2513 } else if (*p == '%') {
2514 if (p != q) {
2515 *p = '\0';
2516 stmt->query.append(dbQueryElement::qExpression, q);
2517 }
2518 switch (*++p) {
2519 case 'd':
2520 case 'i':
2521 stmt->query.append(dbQueryElement::qVarInt4, (void*)offs);
2522 offs += sizeof(cli_int4_t);
2523 break;
2524 case 'f':
2525 offs = DOALIGN(offs, sizeof(cli_real8_t));
2526 stmt->query.append(dbQueryElement::qVarReal8, (void*)offs);
2527 offs += sizeof(cli_real8_t);
2528 break;
2529 case 'p':
2530 offs = DOALIGN(offs, sizeof(cli_oid_t));
2531 stmt->query.append(dbQueryElement::qVarReference, (void*)offs);
2532 offs += sizeof(cli_oid_t);
2533 break;
2534 case 'l':
2535 case 'L':
2536 p += 1;
2537 if (*p != 'd' && *p != 'i') {
2538 statements.free(stmt);
2539 return cli_bad_statement;
2540 }
2541 offs = DOALIGN(offs, sizeof(cli_int8_t));
2542 stmt->query.append(dbQueryElement::qVarInt8, (void*)offs);
2543 offs += sizeof(cli_int8_t);
2544 break;
2545 case 's':
2546 offs = DOALIGN(offs, sizeof(char_t*));
2547 stmt->query.append(dbQueryElement::qVarStringPtr, (void*)offs);
2548 offs += sizeof(char_t*);
2549 break;
2550 case 'R':
2551 offs = DOALIGN(offs, sizeof(cli_coord_t));
2552 stmt->query.append(dbQueryElement::qVarRectangle, (void*)offs);
2553 offs += sizeof(cli_rectangle_t);
2554 break;
2555 case 't':
2556 stmt->query.append((sizeof(cli_time_t) == 4) ? dbQueryElement::qVarInt4 : dbQueryElement::qVarInt8,
2557 (void*)offs);
2558 offs += sizeof(cli_time_t);
2559 break;
2560 default:
2561 statements.free(stmt);
2562 return cli_bad_statement;
2563 }
2564 p += 1;
2565 q = p;
2566 } else {
2567 p += 1;
2568 }
2569 }
2570 if (p != q) {
2571 stmt->query.append(dbQueryElement::qExpression, q);
2572 }
2573 stmt->param_size = (int)offs;
2574 {
2575 dbCriticalSection cs(s->mutex);
2576 stmt->next = s->stmts;
2577 s->stmts = stmt;
2578 }
2579 stmt->prepared = true;
2580 return stmt->id;
2581 }
2582
2583
2584 int cli_execute_query(int statement, int cursor_type, void* record_struct, ...)
2585 {
2586 va_list args;
2587 va_start(args, record_struct);
2588 int rc = dbCLI::instance.execute_query(statement, cursor_type, record_struct, args);
2589 va_end(args);
2590 return rc;
2591 }
2592
2593 int dbCLI::execute_query(int statement, int cursor_type, void* record_struct, va_list params)
2594 {
2595 statement_desc* stmt = statements.get(statement);
2596 if (stmt == NULL || !stmt->prepared) {
2597 return cli_bad_descriptor;
2598 }
2599 stmt->cursor_type = cursor_type;
2600 stmt->oid = 0;
2601 stmt->first_fetch = true;
2602 dbSmallBuffer<char> paramBuf(stmt->param_size);
2603 char* paramBase = paramBuf.base();
2604 int offs = 0;
2605 dbQueryElement* elem = stmt->query.elements;
2606 while (elem != NULL) {
2607 switch (elem->type) {
2608 case dbQueryElement::qVarInt4:
2609 *(cli_int4_t*)(paramBase + offs) = va_arg(params, cli_int4_t);
2610 offs += sizeof(cli_int4_t);
2611 break;
2612 case dbQueryElement::qVarInt8:
2613 offs = DOALIGN(offs, sizeof(cli_int8_t));
2614 *(cli_int8_t*)(paramBase + offs) = va_arg(params, cli_int8_t);
2615 offs += sizeof(cli_int8_t);
2616 break;
2617 case dbQueryElement::qVarReal8:
2618 offs = DOALIGN(offs, sizeof(cli_real8_t));
2619 *(cli_real8_t*)(paramBase + offs) = va_arg(params, cli_real8_t);
2620 offs += sizeof(cli_real8_t);
2621 break;
2622 case dbQueryElement::qVarStringPtr:
2623 offs = DOALIGN(offs, sizeof(char_t*));
2624 *(char_t**)(paramBase + offs) = va_arg(params, char_t*);
2625 offs += sizeof(char_t*);
2626 break;
2627 case dbQueryElement::qVarReference:
2628 offs = DOALIGN(offs, sizeof(cli_oid_t));
2629 *(cli_oid_t*)(paramBase + offs) = va_arg(params, cli_oid_t);
2630 offs += sizeof(cli_oid_t);
2631 break;
2632 case dbQueryElement::qVarRectangle:
2633 offs = DOALIGN(offs, sizeof(cli_coord_t));
2634 *(cli_rectangle_t*)(paramBase + offs) = *va_arg(params, cli_rectangle_t*);
2635 offs += sizeof(cli_rectangle_t);
2636 break;
2637 case dbQueryElement::qVarArrayOfRef:
2638 case dbQueryElement::qVarArrayOfInt4:
2639 case dbQueryElement::qVarArrayOfInt8:
2640 offs = DOALIGN(offs, sizeof(dbAnyArray*));
2641 *(dbAnyArray**)(paramBase + offs) = va_arg(params, dbAnyArray*);
2642 offs += sizeof(dbAnyArray*);
2643 break;
2644 case dbQueryElement::qVarArrayOfRefPtr:
2645 case dbQueryElement::qVarArrayOfInt4Ptr:
2646 case dbQueryElement::qVarArrayOfInt8Ptr:
2647 offs = DOALIGN(offs, sizeof(dbAnyArray**));
2648 *(dbAnyArray***)(paramBase + offs) = va_arg(params, dbAnyArray**);
2649 offs += sizeof(dbAnyArray**);
2650 break;
2651 default:
2652 break;
2653 }
2654 elem = elem->next;
2655 }
2656 stmt->record_struct = record_struct;
2657 stmt->cursor.setTable(stmt->table);
2658 stmt->cursor.reset();
2659 stmt->cursor.setRecord(record_struct);
2660 #ifdef THROW_EXCEPTION_ON_ERROR
2661 try {
2662 #endif
2663 return stmt->cursor.select(stmt->query, (dbCursorType)cursor_type, paramBase);
2664 #ifdef THROW_EXCEPTION_ON_ERROR
2665 } catch (dbException const& x) {
2666 return (x.getErrCode() == dbDatabase::QueryError)
2667 ? cli_bad_statement : cli_runtime_error;
2668 }
2669 #endif
2670 }
2671
2672 int cli_execute_query_ex(int statement, int cursor_type, void* record_struct, int n_params, int* param_types, void** param_values)
2673 {
2674 return dbCLI::instance.execute_query(statement, cursor_type, record_struct, n_params, param_types, param_values);
2675 }
2676
2677 int dbCLI::execute_query(int statement, int cursor_type, void* record_struct, int n_params, int* param_types, void** param_values)
2678 {
2679 statement_desc* stmt = statements.get(statement);
2680 if (stmt == NULL || !stmt->prepared) {
2681 return cli_bad_descriptor;
2682 }
2683 stmt->cursor_type = cursor_type;
2684 stmt->oid = 0;
2685 stmt->first_fetch = true;
2686 dbSmallBuffer<char> paramBuf(stmt->param_size);
2687 int paramIndex = 0;
2688 char* paramBase = paramBuf.base();
2689 int offs = 0;
2690 dbQueryElement* elem = stmt->query.elements;
2691 while (elem != NULL) {
2692 if (elem->type != dbQueryElement::qExpression) {
2693 if (paramIndex >= n_params) {
2694 return cli_unbound_parameter;
2695 }
2696 void* val = param_values[paramIndex];
2697 cli_var_type type = (cli_var_type)param_types[paramIndex];
2698 paramIndex += 1;
2699 switch (elem->type) {
2700 case dbQueryElement::qVarInt4:
2701 switch (type) {
2702 case cli_int1:
2703 *(cli_int4_t*)(paramBase + offs) = *(cli_int1_t*)val;
2704 break;
2705 case cli_int2:
2706 *(cli_int4_t*)(paramBase + offs) = *(cli_int2_t*)val;
2707 break;
2708 case cli_int4:
2709 *(cli_int4_t*)(paramBase + offs) = *(cli_int4_t*)val;
2710 break;
2711 default:
2712 return cli_incompatible_type;
2713 }
2714 offs += sizeof(cli_int4_t);
2715 break;
2716 case dbQueryElement::qVarInt8:
2717 offs = DOALIGN(offs, sizeof(cli_int8_t));
2718 switch (type) {
2719 case cli_int1:
2720 *(cli_int8_t*)(paramBase + offs) = *(cli_int1_t*)val;
2721 break;
2722 case cli_int2:
2723 *(cli_int8_t*)(paramBase + offs) = *(cli_int2_t*)val;
2724 break;
2725 case cli_int4:
2726 *(cli_int8_t*)(paramBase + offs) = *(cli_int4_t*)val;
2727 break;
2728 case cli_int8:
2729 *(cli_int8_t*)(paramBase + offs) = *(cli_int8_t*)val;
2730 break;
2731 default:
2732 return cli_incompatible_type;
2733 }
2734 offs += sizeof(cli_int8_t);
2735 break;
2736 case dbQueryElement::qVarReal8:
2737 offs = DOALIGN(offs, sizeof(cli_real8_t));
2738 switch (type) {
2739 case cli_real4:
2740 *(cli_real8_t*)(paramBase + offs) = *(cli_real4_t*)val;
2741 break;
2742 case cli_real8:
2743 *(cli_real8_t*)(paramBase + offs) = *(cli_real8_t*)val;
2744 break;
2745 default:
2746 return cli_incompatible_type;
2747 }
2748 offs += sizeof(cli_real8_t);
2749 break;
2750 case dbQueryElement::qVarStringPtr:
2751 offs = DOALIGN(offs, sizeof(char_t*));
2752 *(char_t**)(paramBase + offs) = *(char_t**)val;
2753 offs += sizeof(char_t*);
2754 break;
2755 case dbQueryElement::qVarReference:
2756 offs = DOALIGN(offs, sizeof(cli_oid_t));
2757 *(cli_oid_t*)(paramBase + offs) = *(cli_oid_t*)val;
2758 offs += sizeof(cli_oid_t);
2759 break;
2760 case dbQueryElement::qVarRectangle:
2761 offs = DOALIGN(offs, sizeof(cli_coord_t));
2762 *(cli_rectangle_t*)(paramBase + offs) = *(cli_rectangle_t*)val;
2763 offs += sizeof(cli_rectangle_t);
2764 break;
2765 case dbQueryElement::qVarArrayOfRef:
2766 case dbQueryElement::qVarArrayOfInt4:
2767 case dbQueryElement::qVarArrayOfInt8:
2768 offs = DOALIGN(offs, sizeof(dbAnyArray*));
2769 *(dbAnyArray**)(paramBase + offs) = (dbAnyArray*)val;
2770 offs += sizeof(dbAnyArray*);
2771 break;
2772 case dbQueryElement::qVarArrayOfRefPtr:
2773 case dbQueryElement::qVarArrayOfInt4Ptr:
2774 case dbQueryElement::qVarArrayOfInt8Ptr:
2775 offs = DOALIGN(offs, sizeof(dbAnyArray**));
2776 *(dbAnyArray***)(paramBase + offs) = (dbAnyArray**)val;
2777 offs += sizeof(dbAnyArray**);
2778 break;
2779 default:
2780 return cli_incompatible_type;
2781 }
2782 }
2783 elem = elem->next;
2784 }
2785 if (paramIndex != n_params) {
2786 return cli_unbound_parameter;
2787 }
2788 stmt->record_struct = record_struct;
2789 stmt->cursor.setTable(stmt->table);
2790 stmt->cursor.reset();
2791 stmt->cursor.setRecord((byte*)record_struct);
2792 #ifdef THROW_EXCEPTION_ON_ERROR
2793 try {
2794 #endif
2795 return stmt->cursor.select(stmt->query, (dbCursorType)cursor_type, paramBase);
2796 #ifdef THROW_EXCEPTION_ON_ERROR
2797 } catch (dbException const& x) {
2798 return (x.getErrCode() == dbDatabase::QueryError)
2799 ? cli_bad_statement : cli_runtime_error;
2800 }
2801 #endif
2802 }
2803
2804 int cli_insert_struct(int session, char_t const* table_name, void* record_struct, cli_oid_t* oid)
2805 {
2806 return dbCLI::instance.insert_struct(session, table_name, record_struct, oid);
2807 }
2808
2809 int dbCLI::insert_struct(int session, char_t const* table_name, void* record_struct, cli_oid_t* oid)
2810 {
2811 session_desc* s = sessions.get(session);
2812 if (s == NULL) {
2813 return cli_bad_descriptor;
2814 }
2815 dbTableDescriptor* table = s->db->findTableByName(table_name);
2816 if (table == NULL) {
2817 return cli_table_not_found;
2818 }
2819 GB_TRY;
2820 dbAnyReference ref;
2821 if (!s->db->insertRecord(table, &ref, record_struct, false)) {
2822 return cli_not_unique;
2823 }
2824 if (oid != NULL) {
2825 *oid = (cli_oid_t)ref.getOid();
2826 }
2827 GB_CATCH
2828 return cli_ok;
2829 }
2830
2831
2832
2833 int cli_get_field_size(cli_field_descriptor* fields, int field_no)
2834 {
2835 return sizeof_type[fields[field_no].type];
2836 }
2837
2838
2839 int cli_get_field_offset(cli_field_descriptor* fields, int field_no)
2840 {
2841 int offs = 0;
2842 int size = 0;
2843 for (int i = 0; i <= field_no; i++) {
2844 size = sizeof_type[fields[i].type];
2845 offs = DOALIGN(offs, alignof_type[fields[i].type]);
2846 offs += size;
2847 }
2848 return offs - size;
2849 }
2850
2851 void cli_clear_connection_pool()
2852 {
2853 }
2854
2855 cli_transaction_context_t cli_create_transaction_context()
2856 {
2857 return new dbDatabaseThreadContext();
2858 }
2859
2860 void cli_remove_transaction_context(cli_transaction_context_t ctx)
2861 {
2862 delete (dbDatabaseThreadContext*)ctx;
2863 }
2864
2865 int cli_join_transaction(int stmt, cli_transaction_context_t ctx)
2866 {
2867 return dbCLI::instance.join_transaction(stmt, ctx);
2868 }
2869
2870 int dbCLI::join_transaction(int session, cli_transaction_context_t ctx)
2871 {
2872 session_desc* s = sessions.get(session);
2873 if (s == NULL) {
2874 return cli_bad_descriptor;
2875 }
2876 GB_TRY
2877 s->db->attach((dbDatabaseThreadContext*)ctx);
2878 GB_CATCH
2879 return cli_ok;
2880 }
2881
2882 int cli_xml_export(int session, FILE* out, char_t const* const* tables, int n_tables, cli_export_method method)
2883 {
2884 return dbCLI::instance.xml_export(session, out, tables, n_tables, method);
2885 }
2886
2887 int cli_xml_import(int session, FILE* in)
2888 {
2889 return dbCLI::instance.xml_import(session, in);
2890 }
2891
2892 int dbCLI::xml_export(int session, FILE* out, char_t const* const* tables, int n_tables, cli_export_method method)
2893 {
2894 session_desc* s = sessions.get(session);
2895 if (s == NULL) {
2896 return cli_bad_descriptor;
2897 }
2898 GB_TRY
2899 s->db->exportDatabaseToXml(out, tables, n_tables, (dbDatabase::SelectionMethod)method);
2900 GB_CATCH
2901 return cli_ok;
2902 }
2903
2904 int dbCLI::xml_import(int session, FILE* in)
2905 {
2906 session_desc* s = sessions.get(session);
2907 if (s == NULL) {
2908 return cli_bad_descriptor;
2909 }
2910 GB_TRY
2911 return s->db->importDatabaseFromXml(in) ? cli_ok : cli_xml_parse_error;
2912 GB_CATCH
2913 }
2914
2915 int cli_backup(int session, char_t const* file_name, int compactify)
2916 {
2917 return dbCLI::instance.backup(session, file_name, compactify);
2918 }
2919
2920 int cli_schedule_backup(int session, char_t const* file_name, int period)
2921 {
2922 return dbCLI::instance.schedule_backup(session, file_name, period);
2923 }
2924
2925 int dbCLI::backup(int session, char_t const* file_name, int compactify)
2926 {
2927 session_desc* s = sessions.get(session);
2928 if (s == NULL) {
2929 return cli_bad_descriptor;
2930 }
2931 GB_TRY
2932 return s->db->backup(file_name, compactify != 0) ? cli_ok : cli_backup_failed;
2933 GB_CATCH
2934 }
2935
2936 int dbCLI::schedule_backup(int session, char_t const* file_name, int period)
2937 {
2938 session_desc* s = sessions.get(session);
2939 if (s == NULL) {
2940 return cli_bad_descriptor;
2941 }
2942 GB_TRY
2943 s->db->scheduleBackup(file_name, period);
2944 GB_CATCH
2945 return cli_ok;
2946 }
2947
2948 int cli_get_database_size(int session, cli_nat8_t* size)
2949 {
2950 return dbCLI::instance.get_database_size(session, size);
2951 }
2952
2953 int dbCLI::get_database_size(int session, cli_nat8_t* size)
2954 {
2955 session_desc* s = sessions.get(session);
2956 if (s == NULL) {
2957 return cli_bad_descriptor;
2958 }
2959 *size = s->db->getDatabaseSize();
2960 return cli_ok;
2961 }
2962
2963