1 //-< CLI.CPP >-------------------------------------------------------*--------*
2 // FastDB                    Version 1.0         (c) 1999  GARRET    *     ?  *
3 // (Main Memory Database Management System)                          *   /\|  *
4 //                                                                   *  /  \  *
5 //                          Created:     13-Jan-2000  K.A. Knizhnik  * / [] \ *
6 //                          Last update: 13-Jan-2000  K.A. Knizhnik  * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Call level interface client part implementation
9 //-------------------------------------------------------------------*--------*
10 
11 #define INSIDE_FASTDB
12 
13 #include "stdtp.h"
14 #include "sockio.h"
15 #include "repsock.h"
16 #include "sync.h"
17 #include "cli.h"
18 #include "cliproto.h"
19 
20 #include <wchar.h>
21 #include <ctype.h>
22 
23 BEGIN_FASTDB_NAMESPACE
24 
25 struct parameter_binding {
26     parameter_binding* next;
27     char* name;
28     int   var_type;
29     int   var_len;
30     void* var_ptr;
31 
~parameter_bindingparameter_binding32     ~parameter_binding() {
33         delete[] name;
34     }
35 };
36 
37 struct column_binding {
38     column_binding* next;
39     char* name;
40     int   var_type;
41     int*  var_len;
42     void* var_ptr;
43     void* arr_ptr;
44     int   arr_len;
45     cli_column_get_ex get_fnc;
46     cli_column_set_ex set_fnc;
47     void* user_data;
48 
~column_bindingcolumn_binding49     ~column_binding() {
50         delete[] name;
51     }
52 };
53 
54 struct session_desc;
55 
56 #define DEFAULT_BUF_SIZE 256
57 
58 struct statement_desc {
59     int                id;
60     statement_desc*    next;
61     char*              stmt;
62     column_binding*    columns;
63     parameter_binding* params;
64     session_desc*      session;
65     bool               for_update;
66     bool               updated;
67     bool               prepared;
68     bool               autoincrement;
69     cli_oid_t          oid;
70     int                stmt_len;
71     int                n_params;
72     int                n_columns;
73     int                columns_len;
74     char*              buf;
75     size_t             buf_size;
76 
deallocatestatement_desc77     void deallocate() {
78         delete[] stmt;
79         column_binding *cb, *next_cb;
80         for (cb = columns; cb != NULL; cb = next_cb) {
81             next_cb = cb->next;
82             delete cb;
83         }
84         if (buf != NULL) {
85             delete[] buf;
86             buf_size = 0;
87             buf = NULL;
88         }
89         parameter_binding *pb, *next_pb;
90         for (pb = params; pb != NULL; pb = next_pb) {
91             next_pb = pb->next;
92             delete pb;
93         }
94     }
statement_descstatement_desc95     statement_desc(int id, statement_desc* next) {
96         this->id = id;
97         this->next = next;
98         buf = NULL;
99         buf_size = 0;
100     }
statement_descstatement_desc101     statement_desc() {}
102 };
103 
104 struct session_desc {
105     int             id;
106     session_desc*   next;
107     socket_t*       sock;
108     statement_desc* stmts;
109 
session_descsession_desc110     session_desc(int id, session_desc* next) {
111         this->id = id;
112         this->next = next;
113     }
session_descsession_desc114     session_desc() {}
115 };
116 
117 template<class T>
118 class descriptor_table {
119   protected:
120     T**         table;
121     T*          free_desc;
122     int         descriptor_table_size;
123     dbMutex     mutex;
124 
125   public:
descriptor_table()126     descriptor_table() {
127         int i;
128         descriptor_table_size = 16;
129         table = new T*[descriptor_table_size];
130         T* next = NULL;
131         for (i = 0; i < descriptor_table_size; i++) {
132             table[i] = next = new T(i, next);
133         }
134         free_desc = next;
135     }
136 
~descriptor_table()137     ~descriptor_table() {
138         for (int i = 0; i < descriptor_table_size; i++) {
139             delete table[i];
140         }
141         delete[] table;
142     }
143 
get(int desc)144     T* get(int desc) {
145         dbCriticalSection cs(mutex);
146         return (desc >= descriptor_table_size) ? (T*)0 : table[desc];
147     }
148 
allocate()149     T* allocate() {
150         dbCriticalSection cs(mutex);
151         if (free_desc == NULL) {
152             int i, n;
153             T** desc = new T*[descriptor_table_size * 2];
154             memcpy(desc, table, descriptor_table_size*sizeof(T*));
155             delete[] table;
156             table = desc;
157             T* next = NULL;
158             for (i = descriptor_table_size, n = i*2; i < n; i++) {
159                 table[i] = next = new T(i, next);
160             }
161             free_desc = next;
162             descriptor_table_size = n;
163         }
164         T* desc = free_desc;
165         free_desc = desc->next;
166         return desc;
167     }
168 
deallocate(T * desc)169     void deallocate(T* desc) {
170         dbCriticalSection cs(mutex);
171         desc->next = free_desc;
172         free_desc = desc;
173     }
174 };
175 
176 static descriptor_table<session_desc>   sessions;
177 static descriptor_table<statement_desc> statements;
178 
179 END_FASTDB_NAMESPACE
180 USE_FASTDB_NAMESPACE
181 
cli_open(char const * server_url,int max_connect_attempts,int reconnect_timeout_sec)182 int cli_open(char const* server_url,
183              int         max_connect_attempts,
184              int         reconnect_timeout_sec)
185 {
186     socket_t* sock;
187     int n_addresses = 1;
188     char const* start = server_url;
189     char const* end;
190     while ((end = strchr(start, ',')) != NULL) {
191         start = end + 1;
192         n_addresses += 1;
193     }
194     if (n_addresses == 1) {
195         sock = socket_t::connect(server_url,
196                                  socket_t::sock_any_domain,
197                                  max_connect_attempts,
198                                  reconnect_timeout_sec);
199     } else {
200         char** addresses = new char*[n_addresses];
201         start = server_url;
202         for (int i = 0; i < n_addresses; i++) {
203             end = strchr(start, ',');
204             if (end == NULL) {
205                 end = start + strlen(start);
206             }
207             int len = (int)(end - start);
208             char* addr = new char[len+1];
209             memcpy(addr, start, len);
210             addr[len] = '\0';
211             start = end + 1;
212             addresses[i] = addr;
213         }
214         sock = replication_socket_t::connect((char const**)addresses,
215                                              n_addresses,
216                                              max_connect_attempts,
217                                              reconnect_timeout_sec);
218         while (--n_addresses >= 0) {
219             delete[] addresses[n_addresses];
220         }
221         delete[] addresses;
222     }
223     if (!sock->is_ok()) {
224         delete sock;
225         return cli_connection_refused;
226     }
227     session_desc* session = sessions.allocate();
228     session->sock = sock;
229     session->stmts = NULL;
230     return session->id;
231 }
232 
233 
cli_close(int session)234 int cli_close(int session)
235 {
236     statement_desc *stmt, *next;
237     session_desc* s = sessions.get(session);
238     if (s == NULL) {
239         return cli_bad_descriptor;
240     }
241     cli_request req;
242     req.length = sizeof(req);
243     req.cmd = cli_cmd_close_session;
244     req.pack();
245     int result = cli_ok;
246     if (!s->sock->write(&req, sizeof req)) {
247         result = cli_network_error;
248     }
249     delete s->sock;
250     s->sock = NULL;
251     for (stmt = s->stmts; stmt != NULL; stmt = next) {
252         next = stmt->next;
253         stmt->deallocate();
254         statements.deallocate(stmt);
255     }
256     sessions.deallocate(s);
257     return result;
258 }
259 
cli_statement(int session,char const * stmt_str)260 int cli_statement(int session, char const* stmt_str)
261 {
262     session_desc* s = sessions.get(session);
263     if (s == NULL) {
264         return cli_bad_descriptor;
265     }
266     statement_desc* stmt = statements.allocate();
267     stmt->stmt = new char[strlen(stmt_str)+1];
268     stmt->columns = NULL;
269     stmt->params = NULL;
270     stmt->session = s;
271     stmt->for_update = 0;
272     stmt->prepared = false;
273     stmt->n_params = 0;
274     stmt->n_columns = 0;
275     stmt->columns_len = 0;
276     stmt->oid = 0;
277     stmt->next = s->stmts;
278     stmt->updated = false;
279     s->stmts = stmt;
280     char const* p = stmt_str;
281     char* dst = stmt->stmt;
282     parameter_binding** last = &stmt->params;
283     while (*p != '\0') {
284         if (*p == '\'') {
285             do {
286                 do {
287                     *dst++ = *p++;
288                 } while (*p != '\0' && *p != '\'');
289                 *dst++ = *p;
290                 if (*p == '\0') {
291                     *last = NULL;
292                     stmt->deallocate();
293                     statements.deallocate(stmt);
294                     return cli_bad_statement;
295                 }
296             } while (*++p == '\'');
297         } else if (*p == '%') {
298             stmt->n_params += 1;
299             char const* q = p++;
300             while (isalnum((unsigned char)*p) || *p == '_') p += 1;
301             if (*p == '%') {
302                 *last = NULL;
303                 stmt->deallocate();
304                 statements.deallocate(stmt);
305                 return cli_bad_statement;
306             }
307             parameter_binding* pb = new parameter_binding;
308             int len = (int)(p - q);
309             pb->name = new char[len+1];
310             memcpy(pb->name, q, len);
311             pb->name[len] = '\0';
312             *last = pb;
313             last = &pb->next;
314             pb->var_ptr = NULL;
315             *dst++ = '\0';
316         } else {
317             *dst++ = *p++;
318         }
319     }
320     if (dst == stmt->stmt || *(dst-1) != '\0') {
321         *dst++ = '\0';
322     }
323     stmt->stmt_len = (int)(dst - stmt->stmt);
324     *last = NULL;
325     return stmt->id;
326 }
327 
cli_parameter(int statement,char const * param_name,int var_type,void * var_ptr)328 int cli_parameter(int         statement,
329                   char const* param_name,
330                   int         var_type,
331                   void*       var_ptr)
332 {
333     if (var_type != cli_rectangle
334         && var_type != cli_wstring
335         && var_type != cli_pwstring
336         && ((unsigned)var_type >= cli_array_of_oid || var_type == cli_decimal))
337     {
338         return cli_unsupported_type;
339     }
340     statement_desc* s = statements.get(statement);
341     if (s == NULL) {
342         return cli_bad_descriptor;
343     }
344     s->prepared = false;
345     for (parameter_binding* pb = s->params; pb != NULL; pb = pb->next) {
346         if (strcmp(pb->name, param_name) == 0) {
347             pb->var_ptr  = var_ptr;
348             pb->var_type = var_type;
349             return cli_ok;
350         }
351     }
352     return cli_parameter_not_found;
353 }
354 
cli_column(int statement,char const * column_name,int var_type,int * var_len,void * var_ptr)355 int cli_column(int         statement,
356                char const* column_name,
357                int         var_type,
358                int*        var_len,
359                void*       var_ptr)
360 {
361     statement_desc* s = statements.get(statement);
362     if (s == NULL) {
363         return cli_bad_descriptor;
364     }
365     s->prepared = false;
366     column_binding* cb = new column_binding;
367     int len = (int)strlen(column_name) + 1;
368     cb->name = new char[len];
369     s->columns_len += len;
370     cb->next = s->columns;
371     s->columns = cb;
372     s->n_columns += 1;
373     strcpy(cb->name, column_name);
374     cb->var_type = var_type;
375     cb->var_len = var_len;
376     cb->var_ptr = var_ptr;
377     cb->set_fnc = NULL;
378     cb->get_fnc = NULL;
379     return cli_ok;
380 }
381 
cli_array_column(int statement,char const * column_name,int var_type,void * var_ptr,cli_column_set set,cli_column_get get)382 int cli_array_column(int            statement,
383                      char const*    column_name,
384                      int            var_type,
385                      void*          var_ptr,
386                      cli_column_set set,
387                      cli_column_get get)
388 {
389     return cli_array_column_ex(statement, column_name, var_type, var_ptr,
390                                (cli_column_set_ex)set, (cli_column_get_ex)get, NULL);
391 }
392 
cli_array_column_ex(int statement,char const * column_name,int var_type,void * var_ptr,cli_column_set_ex set,cli_column_get_ex get,void * user_data)393 int cli_array_column_ex(int               statement,
394                         char const*       column_name,
395                         int               var_type,
396                         void*             var_ptr,
397                         cli_column_set_ex set,
398                         cli_column_get_ex get,
399                         void*             user_data)
400 {
401     statement_desc* s = statements.get(statement);
402     if (s == NULL) {
403         return cli_bad_descriptor;
404     }
405     if (!((var_type >= cli_asciiz && var_type <= cli_array_of_string)
406           || (var_type >= cli_wstring && var_type <= cli_array_of_wstring)))
407     {
408         return cli_unsupported_type;
409     }
410     s->prepared = false;
411     column_binding* cb = new column_binding;
412     int len = (int)strlen(column_name) + 1;
413     cb->name = new char[len];
414     s->columns_len += len;
415     cb->next = s->columns;
416     s->columns = cb;
417     s->n_columns += 1;
418     strcpy(cb->name, column_name);
419     cb->var_type = var_type;
420     cb->var_len = NULL;
421     cb->var_ptr = var_ptr;
422     cb->set_fnc = set;
423     cb->get_fnc = get;
424     cb->user_data = user_data;
425     return cli_ok;
426 }
427 
cli_fetch_ex(int statement,int cursor_type,cli_cardinality_t * n_fetched_records)428 int cli_fetch_ex(int statement, int cursor_type, cli_cardinality_t* n_fetched_records)
429 {
430     int rc = cli_fetch(statement,  cursor_type);
431     if (rc >= 0) {
432         *n_fetched_records = rc;
433         return cli_ok;
434     }
435     return rc;
436 }
437 
cli_fetch(int statement,int for_update)438 int cli_fetch(int statement, int for_update)
439 {
440     parameter_binding* pb;
441     column_binding*    cb;
442     statement_desc* stmt = statements.get(statement);
443     char *p, *s;
444 
445     if (stmt == NULL) {
446         return cli_bad_descriptor;
447     }
448     stmt->for_update = for_update;
449     size_t msg_size = sizeof(cli_request) + 1;
450     for (pb = stmt->params; pb != NULL; pb = pb->next) {
451         if (pb->var_ptr == NULL) {
452             return cli_unbound_parameter;
453         }
454         if (pb->var_type == cli_asciiz) {
455             msg_size += strlen((char*)pb->var_ptr) + 1;
456         } else if (pb->var_type == cli_pasciiz) {
457             msg_size += strlen(*(char**)pb->var_ptr) + 1;
458         } else if (pb->var_type == cli_wstring) {
459             msg_size += (wcslen((wchar_t*)pb->var_ptr) + 1)*sizeof(wchar_t);
460         } else if (pb->var_type == cli_pwstring) {
461             msg_size += (wcslen(*(wchar_t**)pb->var_ptr) + 1)*sizeof(wchar_t);
462         } else {
463             msg_size += sizeof_type[pb->var_type];
464         }
465     }
466     stmt->oid = 0;
467     if (!stmt->prepared) {
468         msg_size += 4 + stmt->stmt_len + stmt->n_params;
469         msg_size += stmt->columns_len + stmt->n_columns;
470     }
471     dbSmallBuffer buf(msg_size);
472     p = buf;
473     cli_request* req = (cli_request*)p;
474     req->length  = (int)msg_size;
475     req->cmd     = stmt->prepared
476         ? cli_cmd_execute : cli_cmd_prepare_and_execute;
477     req->stmt_id = statement;
478     req->pack();
479     p += sizeof(cli_request);
480 
481     if (!stmt->prepared) {
482         *p++ = stmt->n_params;
483         *p++ = stmt->n_columns;
484         p = pack2(p, stmt->stmt_len + stmt->n_params);
485         pb = stmt->params;
486         char* end = p + stmt->stmt_len + stmt->n_params;
487         char* src = stmt->stmt;
488         while (p < end) {
489             while ((*p++ = *src++) != '\0');
490             if (pb != NULL) {
491                 *p++ = pb->var_type == cli_pasciiz ? cli_asciiz
492                     : pb->var_type == cli_pwstring ? cli_wstring : pb->var_type;
493                 pb = pb->next;
494             }
495         }
496         for (cb = stmt->columns; cb != NULL; cb = cb->next) {
497             *p++ = cb->var_type;
498             s = cb->name;
499             while ((*p++ = *s++) != '\0');
500         }
501     }
502     *p++ = for_update;
503     for (pb = stmt->params; pb != NULL; pb = pb->next) {
504         switch (pb->var_type) {
505           case cli_rectangle:
506             p = pack_rectangle(p, (cli_rectangle_t*)pb->var_ptr);
507             continue;
508           case cli_asciiz:
509             s = (char*)pb->var_ptr;
510             while ((*p++ = *s++) != '\0');
511             continue;
512           case cli_pasciiz:
513             s = *(char**)pb->var_ptr;
514             while ((*p++ = *s++) != '\0');
515             continue;
516           case cli_wstring:
517           {
518               wchar_t* src = (wchar_t*)pb->var_ptr;
519               wchar_t* dst = (wchar_t*)p;
520               while ((*dst++ = *src++) != 0);
521               p = (char*)dst;
522               continue;
523           }
524           case cli_pwstring:
525           {
526               wchar_t* src = *(wchar_t**)pb->var_ptr;
527               wchar_t* dst = (wchar_t*)p;
528               while ((*dst++ = *src++) != 0);
529               p = (char*)dst;
530               continue;
531           }
532           default:
533             switch (sizeof_type[pb->var_type]) {
534               case 1:
535                 *p++ = *(char*)pb->var_ptr;
536                 continue;
537               case 2:
538                 p = pack2(p, *(int2*)pb->var_ptr);
539                 continue;
540               case 4:
541                 p = pack4(p, *(int4*)pb->var_ptr);
542                 continue;
543               case 8:
544                 p = pack8(p, *(db_int8*)pb->var_ptr);
545                 continue;
546             }
547         }
548     }
549     assert(msg_size == (size_t)(p - buf.base()));
550     if (!stmt->session->sock->write(buf, msg_size)) {
551         return cli_network_error;
552     }
553     int4 response;
554     if (!stmt->session->sock->read(&response, sizeof response)) {
555         return cli_network_error;
556     }
557     unpack4(response);
558     if (response >= 0) {
559         stmt->prepared = true;
560     }
561     return response;
562 }
563 
cli_send_columns(int statement,int cmd)564 static int cli_send_columns(int statement, int cmd)
565 {
566     statement_desc* s = statements.get(statement);
567     column_binding* cb;
568     if (s == NULL) {
569         return cli_bad_descriptor;
570     }
571     size_t msg_size = sizeof(cli_request);
572     if (cmd == cli_cmd_update) {
573         if (!s->prepared) {
574             return cli_not_fetched;
575         }
576         if (s->oid == 0) {
577             return cli_not_found;
578         }
579         if (s->updated) {
580             return cli_already_updated;
581         }
582         if (!s->for_update) {
583             return cli_not_update_mode;
584         }
585     } else {
586         if (!s->prepared) {
587             cmd = cli_cmd_prepare_and_insert;
588             msg_size += 1 + s->stmt_len + s->n_columns + s->columns_len;
589         }
590     }
591     s->autoincrement = false;
592     for (cb = s->columns; cb != NULL; cb = cb->next) {
593         if (cb->get_fnc != NULL) {
594             cb->arr_ptr = cb->get_fnc(cb->var_type, cb->var_ptr, &cb->arr_len,
595                                       cb->name, statement, cb->user_data);
596             int len = cb->arr_len;
597             msg_size += 4;
598             if (cb->var_type == cli_array_of_string) {
599                 char** p = (char**)cb->arr_ptr;
600                 while (--len >= 0) {
601                     msg_size += strlen(*p++) + 1;
602                 }
603             } else if (cb->var_type == cli_array_of_wstring) {
604                 wchar_t** p = (wchar_t**)cb->arr_ptr;
605                 while (--len >= 0) {
606                     msg_size += (wcslen(*p++) + 1)*sizeof(wchar_t);
607                 }
608             } else if (cb->var_type == cli_wstring || cb->var_type == cli_pwstring) {
609                 msg_size += len * sizeof(wchar_t);
610             } else if (cb->var_type >= cli_array_of_oid) {
611                 msg_size += len * sizeof_type[cb->var_type - cli_array_of_oid];
612             } else {
613                 msg_size += len;
614             }
615         } else {
616             switch (cb->var_type) {
617               case cli_autoincrement:
618                 s->autoincrement = true;
619                 break;
620               case cli_asciiz:
621                 msg_size += 4 + (strlen((char*)cb->var_ptr) + 1);
622                 break;
623               case cli_pasciiz:
624                 msg_size += 4 + (strlen(*(char**)cb->var_ptr) + 1);
625                 break;
626               case cli_wstring:
627                 msg_size += 4 + (wcslen((wchar_t*)cb->var_ptr) + 1)*sizeof(wchar_t);
628                 break;
629               case cli_pwstring:
630                 msg_size += 4 + (wcslen(*(wchar_t**)cb->var_ptr) + 1)*sizeof(wchar_t);
631                 break;
632               case cli_array_of_string:
633               {
634                 char** p = (char**)cb->var_ptr;
635                 int len;
636                 msg_size += 4;
637                 for (len = *cb->var_len; --len >= 0;) {
638                     msg_size += (strlen(*p++) + 1);
639                 }
640                 break;
641               }
642               case cli_array_of_wstring:
643               {
644                 wchar_t** p = (wchar_t**)cb->var_ptr;
645                 int len;
646                 msg_size += 4;
647                 for (len = *cb->var_len; --len >= 0;) {
648                     msg_size += (wcslen(*p++) + 1)*sizeof(wchar_t);
649                 }
650                 break;
651               }
652               default:
653                 if (cb->var_type >= cli_array_of_oid && cb->var_type < cli_array_of_string) {
654                     msg_size += 4 + *cb->var_len * sizeof_type[cb->var_type-cli_array_of_oid];
655                 } else {
656                     msg_size += sizeof_type[cb->var_type];
657                 }
658             }
659         }
660     }
661     dbSmallBuffer buf(msg_size);
662     char* p = buf;
663     cli_request* req = (cli_request*)p;
664     req->length  = (int)msg_size;
665     req->cmd     = cmd;
666     req->stmt_id = statement;
667     req->pack();
668     p += sizeof(cli_request);
669     if (cmd == cli_cmd_prepare_and_insert) {
670         char* cmd = s->stmt;
671         while ((*p++ = *cmd++) != '\0');
672         *p++ = s->n_columns;
673         for (cb = s->columns; cb != NULL; cb = cb->next) {
674             char* src = cb->name;
675             *p++ = cb->var_type;
676             while ((*p++ = *src++) != '\0');
677         }
678     }
679     for (cb = s->columns; cb != NULL; cb = cb->next) {
680         int n = 0;
681         char* src;
682         if (cb->get_fnc != NULL) {
683             src = (char*)cb->arr_ptr;
684             n = cb->arr_len;
685         } else {
686             src = (char*)cb->var_ptr;
687             if (cb->var_type >= cli_array_of_oid && (cb->var_type <= cli_array_of_string || cb->var_type == cli_array_of_wstring)) {
688                 n = *cb->var_len;
689             }
690         }
691         if (cb->var_type >= cli_array_of_oid && (cb->var_type <= cli_array_of_string || cb->var_type == cli_array_of_wstring)) {
692             p = pack4(p, n);
693             if (cb->var_type == cli_array_of_string) {
694                 while (--n >= 0) {
695                     strcpy(p, *(char**)src);
696                     p += strlen(p) + 1;
697                     src += sizeof(char*);
698                 }
699             } else if (cb->var_type == cli_array_of_wstring) {
700                 while (--n >= 0) {
701                     wcscpy((wchar_t*)p, *(wchar_t**)src);
702                     p += (wcslen((wchar_t*)p) + 1)*sizeof(wchar_t);
703                     src += sizeof(wchar_t*);
704                 }
705             } else {
706                 switch (sizeof_type[cb->var_type-cli_array_of_oid]) {
707                   case 2:
708                     while (--n >= 0) {
709                         p = pack2(p, src);
710                         src += 2;
711                     }
712                     break;
713                   case 4:
714                     while (--n >= 0) {
715                         p = pack4(p, src);
716                         src += 4;
717                     }
718                     break;
719                   case 8:
720                     while (--n >= 0) {
721                         p = pack8(p, src);
722                         src += 8;
723                     }
724                     break;
725                   default:
726                     memcpy(p, src, n);
727                     p += n;
728                 }
729             }
730         } else if (cb->var_type == cli_asciiz) {
731             p = pack4(p, (int)strlen(src)+1);
732             while ((*p++ = *src++) != 0);
733         } else if (cb->var_type == cli_pasciiz) {
734             src = *(char**)src;
735             p = pack4(p, (int)strlen(src)+1);
736             while ((*p++ = *src++) != 0);
737         } else if (cb->var_type == cli_wstring) {
738             wchar_t* body = (wchar_t*)src;
739             p = pack4(p, (int)wcslen(body)+1);
740             wchar_t* dst = (wchar_t*)p;
741             while ((*dst++ = *body++) != 0);
742             p = (char*)dst;
743         } else if (cb->var_type == cli_pwstring) {
744             wchar_t* body = *(wchar_t**)src;
745             p = pack4(p, (int)wcslen(body)+1);
746             wchar_t* dst = (wchar_t*)p;
747             while ((*dst++ = *body++) != 0);
748             p = (char*)dst;
749         } else if (cb->var_type == cli_rectangle) {
750             p = pack_rectangle(p, (cli_rectangle_t*)src);
751         } else if (cb->var_type != cli_autoincrement) {
752             switch (sizeof_type[cb->var_type]) {
753               case 2:
754                 p = pack2(p, src);
755                 break;
756               case 4:
757                 p = pack4(p, src);
758                 break;
759               case 8:
760                 p = pack8(p, src);
761                 break;
762               default:
763                 *p++ = *src;
764             }
765         }
766     }
767     assert((size_t)(p - buf.base()) == msg_size);
768     if (!s->session->sock->write(buf, msg_size)) {
769         return cli_network_error;
770     }
771     return cli_ok;
772 }
773 
cli_insert(int statement,cli_oid_t * oid)774 int cli_insert(int statement, cli_oid_t* oid)
775 {
776     int rc = cli_send_columns(statement, cli_cmd_insert);
777     if (rc == cli_ok) {
778         char buf[sizeof(cli_oid_t) + 8];
779         statement_desc* s = statements.get(statement);
780         if (!s->session->sock->read(buf, sizeof buf)) {
781             rc = cli_network_error;
782         } else {
783             rc = unpack4(buf);
784             s->prepared = true;
785             s->oid = unpack_oid(buf + 8);
786             if (oid != NULL) {
787                 *oid = s->oid;
788             }
789            if (s->autoincrement) {
790                int4 rowid = unpack4(buf + 4);
791                for (column_binding* cb = s->columns; cb != NULL; cb = cb->next) {
792                    if (cb->var_type == cli_autoincrement) {
793                        *(int4*)cb->var_ptr = rowid;
794                    }
795                }
796            }
797         }
798     }
799     return rc;
800 }
801 
cli_update(int statement)802 int cli_update(int statement)
803 {
804     int rc = cli_send_columns(statement, cli_cmd_update);
805     if (rc == cli_ok) {
806         int4 response;
807         statement_desc* s = statements.get(statement);
808         s->updated = true;
809         if (!s->session->sock->read(&response, sizeof response)) {
810             rc = cli_network_error;
811         } else {
812             unpack4(response);
813             rc = response;
814         }
815     }
816     return rc;
817 }
818 
cli_get(int statement,int cmd,cli_oid_t value=0)819 static int cli_get(int statement, int cmd, cli_oid_t value = 0)
820 {
821     statement_desc* s = statements.get(statement);
822     if (s == NULL) {
823         return cli_bad_descriptor;
824     }
825     if (!s->prepared) {
826         return cli_not_fetched;
827     }
828     struct get_req {
829         cli_request req;
830         cli_oid_t   value;
831     } get;
832     int length = sizeof(cli_request);
833     if (cmd == cli_cmd_skip) {
834         length += 4;
835         pack4((char*)(&get.req+1), (int)value);
836     } else if (cmd == cli_cmd_seek) {
837         length += sizeof(cli_oid_t);
838         pack_oid((char*)(&get.req+1), value);
839     }
840     get.req.length  = length;
841     get.req.cmd     = cmd;
842     get.req.stmt_id = statement;
843     get.req.pack();
844     if (!s->session->sock->write(&get.req, length)) {
845         return cli_network_error;
846     }
847     int4 response;
848     if (!s->session->sock->read(&response, sizeof response)) {
849         return cli_network_error;
850     }
851     unpack4(response);
852     if (response <= 0) {
853         return response;
854     }
855     if (s->buf_size < (size_t)response-4) {
856         delete[] s->buf;
857         s->buf_size = response-4 < DEFAULT_BUF_SIZE ? DEFAULT_BUF_SIZE : response-4;
858         s->buf = new char[s->buf_size];
859     }
860     char* buf = s->buf;
861     if (!s->session->sock->read(buf, response-4)) {
862         return cli_network_error;
863     }
864     char* p = buf;
865     int result = cli_ok;
866     if (cmd == cli_cmd_seek) {
867         s->oid = value;
868     } else {
869         s->oid = unpack_oid(p);
870         if (s->oid == 0) {
871             return cli_not_found;
872         }
873     }
874     p += sizeof(cli_oid_t);
875     for (column_binding* cb = s->columns; cb != NULL; cb = cb->next) {
876         int type = *p++;
877         if (cb->var_type == cli_any) {
878             cb->var_type = type;
879         } else {
880             assert(cb->var_type == type);
881         }
882         if (cb->set_fnc != NULL) {
883             int len = unpack4(p);
884             p += 4;
885             char* dst = (char*)cb->set_fnc(cb->var_type, cb->var_ptr, len,
886                                            cb->name, statement, p, cb->user_data);
887             if (dst == NULL) {
888                 continue;
889             }
890             if (cb->var_type == cli_array_of_string) {
891                 char** s = (char**)dst;
892                 while (--len >= 0) {
893                     *s++ = p;
894                     p += strlen(p) + 1;
895                 }
896             } else if (cb->var_type == cli_array_of_wstring) {
897                 wchar_t** s = (wchar_t**)dst;
898                 while (--len >= 0) {
899                     *s++ = (wchar_t*)p;
900                     p += (wcslen((wchar_t*)p) + 1)*sizeof(wchar_t);
901                 }
902             } else if (cb->var_type >= cli_array_of_oid && cb->var_type < cli_array_of_string) {
903                 switch (sizeof_type[cb->var_type-cli_array_of_oid]) {
904                   case 2:
905                     while (--len >= 0) {
906                         p = unpack2(dst, p);
907                         dst += 2;
908                     }
909                     break;
910                   case 4:
911                     while (--len >= 0) {
912                         p = unpack4(dst, p);
913                         dst += 4;
914                     }
915                     break;
916                   case 8:
917                     while (--len >= 0) {
918                         p = unpack8(dst, p);
919                         dst += 8;
920                     }
921                     break;
922                   default:
923                     memcpy(dst, p, len);
924                     p += len;
925                 }
926             } else {
927                 memcpy(dst, p, len);
928                 p += len;
929             }
930         } else {
931             if (cb->var_type >= cli_asciiz && (cb->var_type <= cli_array_of_string || cb->var_type == cli_array_of_wstring)) {
932                 int len = unpack4(p);
933                 p += 4;
934                 char* dst = (char*)cb->var_ptr;
935                 char* src = p;
936                 int n = len;
937                 if (cb->var_len != NULL) {
938                     if (n > *cb->var_len) {
939                         n = *cb->var_len;
940                     }
941                     *cb->var_len = n;
942                 }
943                 if (cb->var_type == cli_wstring || cb->var_type == cli_pwstring) {
944                     if (cb->var_type == cli_pwstring) {
945                         dst = *(char**)dst;
946                     }
947                     memcpy(dst, p, n*sizeof(wchar_t));
948                     p += len*sizeof(wchar_t);
949                 } else if (cb->var_type >= cli_array_of_oid) {
950                     if (cb->var_type == cli_array_of_string) {
951                         char** s = (char**)dst;
952                         len -= n;
953                         while (--n >= 0) {
954                             *s++ = p;
955                             p += strlen(p) + 1;
956                         }
957                         while (--len >= 0) {
958                             p += strlen(p) + 1;
959                         }
960                     } else if (cb->var_type == cli_array_of_wstring) {
961                         wchar_t** s = (wchar_t**)dst;
962                         len -= n;
963                         while (--n >= 0) {
964                             *s++ = (wchar_t*)p;
965                             p += (wcslen((wchar_t*)p) + 1)*sizeof(wchar_t);
966                         }
967                         while (--len >= 0) {
968                             p += (wcslen((wchar_t*)p) + 1)*sizeof(wchar_t);
969                         }
970                     } else {
971                         switch (sizeof_type[cb->var_type-cli_array_of_oid]) {
972                           case 2:
973                             while (--n >= 0) {
974                                 src = unpack2(dst, src);
975                                 dst += 2;
976                             }
977                             p += len*2;
978                             break;
979                           case 4:
980                             while (--n >= 0) {
981                                 src = unpack4(dst, src);
982                                 dst += 4;
983                             }
984                             p += len*4;
985                             break;
986                           case 8:
987                             while (--n >= 0) {
988                                 src = unpack8(dst, src);
989                                 dst += 8;
990                             }
991                             p += len*8;
992                             break;
993                           default:
994                             memcpy(dst, p, n);
995                             p += len;
996                         }
997                     }
998                 } else {
999                     if (cb->var_type == cli_pasciiz) {
1000                         dst = *(char**)dst;
1001                     }
1002                     memcpy(dst, p, n);
1003                     p += len;
1004                 }
1005             } else if (cb->var_type == cli_rectangle) {
1006                 p = unpack_rectangle((cli_rectangle_t*)cb->var_ptr, p);
1007             } else {
1008                 switch (sizeof_type[cb->var_type]) {
1009                   case 2:
1010                     p = unpack2((char*)cb->var_ptr, p);
1011                     break;
1012                   case 4:
1013                     p = unpack4((char*)cb->var_ptr, p);
1014                     break;
1015                   case 8:
1016                     p = unpack8((char*)cb->var_ptr, p);
1017                     break;
1018                   default:
1019                     *(char*)cb->var_ptr = *p++;
1020                 }
1021             }
1022         }
1023     }
1024     s->updated = false;
1025     return result;
1026 }
1027 
cli_get_first(int statement)1028 int cli_get_first(int statement)
1029 {
1030     return cli_get(statement, cli_cmd_get_first);
1031 }
1032 
cli_get_last(int statement)1033 int cli_get_last(int statement)
1034 {
1035     return cli_get(statement, cli_cmd_get_last);
1036 }
1037 
cli_get_next(int statement)1038 int cli_get_next(int statement)
1039 {
1040     return cli_get(statement, cli_cmd_get_next);
1041 }
1042 
cli_get_prev(int statement)1043 int cli_get_prev(int statement)
1044 {
1045     return cli_get(statement, cli_cmd_get_prev);
1046 }
1047 
cli_skip(int statement,int n)1048 int cli_skip(int statement, int n)
1049 {
1050     return cli_get(statement, cli_cmd_skip, n);
1051 }
1052 
cli_seek(int statement,cli_oid_t oid)1053 int cli_seek(int statement, cli_oid_t oid)
1054 {
1055     return cli_get(statement, cli_cmd_seek, oid);
1056 }
1057 
1058 
send_receive(int statement,int cmd)1059 static int send_receive(int statement, int cmd)
1060 {
1061     statement_desc* s = statements.get(statement);
1062     if (s == NULL) {
1063         return cli_bad_descriptor;
1064     }
1065     if (!s->prepared) {
1066         return cli_not_fetched;
1067     }
1068     cli_request req;
1069     req.length = sizeof(req);
1070     req.cmd = cmd;
1071     req.stmt_id = statement;
1072     req.pack();
1073     int4 response = cli_ok;
1074     if (!s->session->sock->write(&req, sizeof req)) {
1075         return cli_network_error;
1076     }
1077     if (!s->session->sock->read(&response, sizeof response)) {
1078         return cli_network_error;
1079     }
1080     unpack4(response);
1081     return response;
1082 }
1083 
cli_freeze(int statement)1084 int cli_freeze(int statement)
1085 {
1086     return send_receive(statement, cli_cmd_freeze);
1087 }
1088 
cli_unfreeze(int statement)1089 int cli_unfreeze(int statement)
1090 {
1091     return send_receive(statement, cli_cmd_unfreeze);
1092 }
1093 
cli_get_oid(int statement)1094 cli_oid_t cli_get_oid(int statement)
1095 {
1096     statement_desc* s = statements.get(statement);
1097     if (s == NULL) {
1098         return 0;
1099     }
1100     return s->oid;
1101 }
1102 
1103 
cli_send_command(int session,int statement,int cmd)1104 static int cli_send_command(int session, int statement, int cmd)
1105 {
1106     session_desc* s = sessions.get(session);
1107     if (s == NULL) {
1108         return cli_bad_descriptor;
1109     }
1110     cli_request req;
1111     req.length  = sizeof(cli_request);
1112     req.cmd     = cmd;
1113     req.stmt_id = statement;
1114     req.pack();
1115     if (!s->sock->write(&req, sizeof req)) {
1116         return cli_network_error;
1117     }
1118     int4 response;
1119     if (!s->sock->read(&response, sizeof response)) {
1120         return cli_network_error;
1121     }
1122     unpack4(response);
1123     return response;
1124 }
1125 
cli_close_cursor(int statement)1126 int cli_close_cursor(int statement)
1127 {
1128     return cli_ok;
1129 }
1130 
cli_free(int statement)1131 int cli_free(int statement)
1132 {
1133     statement_desc* stmt = statements.get(statement);
1134     session_desc* s = stmt->session;
1135     if (s == NULL) {
1136         return cli_bad_descriptor;
1137     }
1138     statement_desc *sp, **spp = &s->stmts;
1139     while ((sp = *spp) != stmt) {
1140         if (sp == NULL) {
1141             return cli_bad_descriptor;
1142         }
1143         spp = &sp->next;
1144     }
1145     *spp = stmt->next;
1146     stmt->deallocate();
1147     statements.deallocate(stmt);
1148     cli_request req;
1149     req.length  = sizeof(cli_request);
1150     req.cmd     = cli_cmd_free_statement;
1151     req.stmt_id = statement;
1152     req.pack();
1153     if (!s->sock->write(&req, sizeof req)) {
1154         return cli_network_error;
1155     }
1156     return cli_ok;
1157 }
1158 
cli_lock(int session)1159 int cli_lock(int session)
1160 {
1161     session_desc* s = sessions.get(session);
1162     if (s == NULL) {
1163         return cli_bad_descriptor;
1164     }
1165     cli_request req;
1166     req.length = sizeof(req);
1167     req.cmd = cli_cmd_lock;
1168     req.stmt_id = 0;
1169     req.pack();
1170     return s->sock->write(&req, sizeof req) ? cli_ok : cli_network_error;
1171 }
1172 
1173 
cli_commit(int session)1174 int cli_commit(int session)
1175 {
1176     return cli_send_command(session, 0, cli_cmd_commit);
1177 }
1178 
cli_precommit(int session)1179 int cli_precommit(int session)
1180 {
1181     return cli_send_command(session, 0, cli_cmd_precommit);
1182 }
1183 
cli_abort(int session)1184 int cli_abort(int session)
1185 {
1186     return cli_send_command(session, 0, cli_cmd_abort);
1187 }
1188 
cli_remove(int statement)1189 int cli_remove(int statement)
1190 {
1191     statement_desc* s = statements.get(statement);
1192     if (s == NULL) {
1193         return cli_bad_descriptor;
1194     }
1195     if (s->oid == 0) {
1196         return cli_not_found;
1197     }
1198     if (!s->for_update) {
1199         return cli_not_update_mode;
1200     }
1201     return cli_send_command(s->session->id, s->id, cli_cmd_remove);
1202 }
1203 
cli_remove_current(int statement)1204 int cli_remove_current(int statement)
1205 {
1206     statement_desc* s = statements.get(statement);
1207     if (s == NULL) {
1208         return cli_bad_descriptor;
1209     }
1210     if (s->oid == 0) {
1211         return cli_not_found;
1212     }
1213     if (!s->for_update) {
1214         return cli_not_update_mode;
1215     }
1216     return cli_send_command(s->session->id, s->id, cli_cmd_remove_current);
1217 }
1218 
1219 
cli_describe(int session,char const * table,cli_field_descriptor ** fields)1220 int cli_describe(int session, char const* table, cli_field_descriptor** fields)
1221 {
1222     int len = (int)(sizeof(cli_request) + strlen(table) + 1);
1223     dbSmallBuffer buf(len);
1224     cli_request* req = (cli_request*)buf.base();
1225     req->length = len;
1226     req->cmd    = cli_cmd_describe_table;
1227     req->stmt_id = 0;
1228     strcpy((char*)(req+1), table);
1229     session_desc* s = sessions.get(session);
1230     if (s == NULL) {
1231         return cli_bad_descriptor;
1232     }
1233     req->pack();
1234     if (!s->sock->write(buf, len)) {
1235         return cli_network_error;
1236     }
1237     int4 response[2];
1238     if (!s->sock->read(&response, sizeof response)) {
1239         return cli_network_error;
1240     }
1241     unpack4(response[0]);
1242     unpack4(response[1]);
1243     len = response[0];
1244     int nFields = response[1];
1245     if (nFields == -1) {
1246         return cli_table_not_found;
1247     }
1248     char* p = (char*)malloc(nFields*sizeof(cli_field_descriptor) + len);
1249     cli_field_descriptor* fp = (cli_field_descriptor*)p;
1250     p += nFields*sizeof(cli_field_descriptor);
1251     if (!s->sock->read(p, len)) {
1252         return cli_network_error;
1253     }
1254     *fields = fp;
1255     for (int i = nFields; --i >= 0; fp++) {
1256         fp->type = (enum cli_var_type)*p++;
1257         fp->flags = *p++ & 0xFF;
1258         fp->name = p;
1259         p += strlen(p) + 1;
1260         if (*p != 0) {
1261             fp->refTableName = p;
1262         } else {
1263             fp->refTableName = NULL;
1264         }
1265         p += strlen(p) + 1;
1266         if (*p != 0) {
1267             fp->inverseRefFieldName = p;
1268         } else {
1269             fp->inverseRefFieldName = NULL;
1270         }
1271         p += strlen(p) + 1;
1272     }
1273     return nFields;
1274 }
1275 
cli_describe_layout(int session,char const * table,cli_field_layout ** fields,int * rec_size)1276 int cli_describe_layout(int session, char const* table, cli_field_layout** fields, int* rec_size)
1277 {
1278     return cli_not_implemented;
1279 }
1280 
cli_show_tables(int session,cli_table_descriptor ** tables)1281 int cli_show_tables(int session, cli_table_descriptor** tables)
1282 {
1283     session_desc* s = sessions.get(session);
1284     if (s == NULL) {
1285         return cli_bad_descriptor;
1286     }
1287     cli_request req;
1288     req.length  = sizeof(cli_request);
1289     req.cmd     = cli_cmd_show_tables;
1290     req.stmt_id = 0;
1291     req.pack();
1292     if (!s->sock->write(&req, sizeof req)) {
1293         return cli_network_error;
1294     }
1295     int4 response[2];
1296     if (!s->sock->read(&response, sizeof response)) {
1297         return cli_network_error;
1298     }
1299     unpack4(response[0]);
1300     unpack4(response[1]);
1301     int len = response[0];
1302     int nTables = response[1];
1303     if (nTables == -1) {
1304         return cli_table_not_found;
1305     }
1306     char* p = (char*)malloc(nTables*sizeof(cli_table_descriptor) + len);
1307     cli_table_descriptor* fp = (cli_table_descriptor*)p;
1308     p += nTables*sizeof(cli_table_descriptor);
1309     if (!s->sock->read(p, len)) {
1310         free(p);
1311         return cli_network_error;
1312     }
1313     *tables = fp;
1314     for (int i = nTables; --i >= 0; fp++) {
1315         fp->name = (char*)p;
1316         p += strlen((char*)p)+1;
1317     }
1318     return nTables;
1319 }
1320 
1321 
cli_create(char_t const * databaseName,char_t const * filePath,unsigned transactionCommitDelay,int openAttr,size_t initDatabaseSize,size_t extensionQuantum,size_t initIndexSize,size_t fileSizeLimit)1322 int cli_create(char_t const* databaseName,
1323                char_t const* filePath,
1324                unsigned    transactionCommitDelay,
1325                int         openAttr,
1326                size_t      initDatabaseSize,
1327                size_t      extensionQuantum,
1328                size_t      initIndexSize,
1329                size_t      fileSizeLimit)
1330 {
1331     return cli_bad_address;
1332 }
1333 
1334 
cli_update_table(int cmd,int session,char const * tableName,int nColumns,cli_field_descriptor * columns)1335 static int cli_update_table(int cmd, int session, char const* tableName, int nColumns,
1336                             cli_field_descriptor* columns)
1337 {
1338     int i;
1339     session_desc* s = sessions.get(session);
1340     if (s == NULL) {
1341         return cli_bad_descriptor;
1342     }
1343     size_t size = sizeof(cli_request) + 4 + strlen(tableName)+1;
1344     for (i = 0; i < nColumns; i++) {
1345         size += 2 + (strlen(columns[i].name)+3);
1346         if (columns[i].refTableName != NULL) {
1347             size += strlen(columns[i].refTableName);
1348         }
1349         if (columns[i].inverseRefFieldName != NULL) {
1350             size += strlen(columns[i].inverseRefFieldName);
1351         }
1352     }
1353     dbSmallBuffer buf(size);
1354     cli_request* req = (cli_request*)buf.base();
1355     req->length  = (int)size;
1356     req->cmd     = cmd;
1357     req->stmt_id = 0;
1358     char* dst = (char*)(req + 1);
1359     strcpy(dst, tableName);
1360     dst += strlen(dst) + 1;
1361     *dst++ = (char)nColumns;
1362     for (i = 0; i < nColumns; i++) {
1363         *dst++ = (char)columns[i].type;
1364         *dst++ = (char)columns[i].flags;
1365         strcpy(dst, columns[i].name);
1366         dst += strlen(dst) + 1;
1367         if (columns[i].refTableName != NULL) {
1368             strcpy(dst, columns[i].refTableName);
1369             dst += strlen(dst) + 1;
1370         } else {
1371             *dst++ = 0;
1372         }
1373         if (columns[i].inverseRefFieldName != NULL) {
1374             strcpy(dst, columns[i].inverseRefFieldName);
1375             dst += strlen(dst) + 1;
1376         } else {
1377             *dst++ = 0;
1378         }
1379     }
1380     req->pack();
1381     if (!s->sock->write(buf, size)) {
1382         return cli_network_error;
1383     }
1384     int4 response;
1385     if (!s->sock->read(&response, sizeof response)) {
1386         return cli_network_error;
1387     }
1388     unpack4(response);
1389     return response;
1390 }
1391 
cli_create_table(int session,char const * tableName,int nColumns,cli_field_descriptor * columns)1392 int cli_create_table(int session, char const* tableName, int nColumns,
1393                      cli_field_descriptor* columns)
1394 {
1395     return cli_update_table(cli_cmd_create_table, session, tableName, nColumns, columns);
1396 }
1397 
cli_alter_table(int session,char const * tableName,int nColumns,cli_field_descriptor * columns)1398 int cli_alter_table(int session, char const* tableName, int nColumns,
1399                      cli_field_descriptor* columns)
1400 {
1401     return cli_update_table(cli_cmd_alter_table, session, tableName, nColumns, columns);
1402 }
1403 
cli_drop_table(int session,char const * tableName)1404 int cli_drop_table(int session, char const* tableName)
1405 {
1406     session_desc* s = sessions.get(session);
1407     if (s == NULL) {
1408         return cli_bad_descriptor;
1409     }
1410     int size = (int)(sizeof(cli_request) + strlen(tableName) + 1);
1411     dbSmallBuffer buf(size);
1412     cli_request* req = (cli_request*)buf.base();
1413     req->length  = size;
1414     req->cmd     = cli_cmd_drop_table;
1415     req->stmt_id = 0;
1416     strcpy((char*)(req + 1), tableName);
1417     req->pack();
1418     if (!s->sock->write(buf, size)) {
1419         return cli_network_error;
1420     }
1421     int4 response;
1422     if (!s->sock->read(&response, sizeof response)) {
1423         return cli_network_error;
1424     }
1425     unpack4(response);
1426     return response;
1427 }
1428 
cli_alter_index(int session,char const * tableName,char const * fieldName,int newFlags)1429 int cli_alter_index(int session, char const* tableName, char const* fieldName, int newFlags)
1430 {
1431     session_desc* s = sessions.get(session);
1432     if (s == NULL) {
1433         return cli_bad_descriptor;
1434     }
1435     int size = (int)(sizeof(cli_request) + 1 + strlen(tableName)+strlen(fieldName)+2);
1436     dbSmallBuffer buf(size);
1437     cli_request* req = (cli_request*)buf.base();
1438     req->length  = size;
1439     req->cmd     = cli_cmd_alter_index;
1440     req->stmt_id = 0;
1441     char* dst = (char*)(req + 1);
1442     strcpy(dst, tableName);
1443     dst += strlen(dst) + 1;
1444     strcpy(dst, fieldName);
1445     dst += strlen(dst) + 1;
1446     *dst++ = newFlags;
1447     req->pack();
1448     if (!s->sock->write(buf, size)) {
1449         return cli_network_error;
1450     }
1451     int4 response;
1452     if (!s->sock->read(&response, sizeof response)) {
1453         return cli_network_error;
1454     }
1455     unpack4(response);
1456     return response;
1457 }
1458 
1459 
cli_set_error_handler(int session,cli_error_handler new_handler,void * context)1460 cli_error_handler cli_set_error_handler(int session, cli_error_handler new_handler, void* context)
1461 {
1462     return NULL;
1463 }
1464 
cli_create_replication_node(int nodeId,int nServers,char * nodeNames[],char const * databaseName,char const * filePath,int openAttr,size_t initDatabaseSize,size_t extensionQuantum,size_t initIndexSize,size_t fileSizeLimit)1465 int cli_create_replication_node(int         nodeId,
1466                                 int         nServers,
1467                                 char*       nodeNames[],
1468                                 char const* databaseName,
1469                                 char const* filePath,
1470                                 int         openAttr,
1471                                 size_t      initDatabaseSize,
1472                                 size_t      extensionQuantum,
1473                                 size_t      initIndexSize,
1474                                 size_t      fileSizeLimit)
1475 {
1476     return cli_not_implemented;
1477 }
1478 
cli_attach(int session)1479 int cli_attach(int session)
1480 {
1481     return cli_not_implemented;
1482 }
1483 
cli_detach(int session,int detach_mode)1484 int cli_detach(int session, int detach_mode)
1485 {
1486     return cli_not_implemented;
1487 }
1488 
cli_free_memory(int,void * ptr)1489 void cli_free_memory(int, void* ptr)
1490 {
1491     free(ptr);
1492 }
1493 
cli_get_database_state(int session,cli_database_monitor * monitor)1494 int cli_get_database_state(int session, cli_database_monitor* monitor)
1495 {
1496     return cli_not_implemented;
1497 }
1498 
cli_set_trace_function(cli_trace_function_t)1499 void cli_set_trace_function(cli_trace_function_t)
1500 {
1501 }
1502 
cli_prepare_query(int session,char const * query)1503 int cli_prepare_query(int session, char const* query)
1504 {
1505     return cli_not_implemented;
1506 }
1507 
cli_execute_query(int statement,int for_update,void * record_struct,...)1508 int cli_execute_query(int statement, int for_update, void* record_struct, ...)
1509 {
1510     return cli_not_implemented;
1511 }
1512 
cli_execute_query_ex(int statement,int for_update,void * record_struct,int n_params,int * param_types,void ** param_value)1513 int cli_execute_query_ex(int statement, int for_update, void* record_struct, int n_params, int* param_types, void** param_value)
1514 {
1515     return cli_not_implemented;
1516 }
1517 
cli_insert_struct(int session,char const * table_name,void * record_struct,cli_oid_t * oid)1518 int cli_insert_struct(int session, char const* table_name, void* record_struct, cli_oid_t* oid)
1519 {
1520     return cli_not_implemented;
1521 }
1522 
cli_get_field_size(cli_field_descriptor * fields,int field_no)1523 int cli_get_field_size(cli_field_descriptor* fields, int field_no)
1524 {
1525     return sizeof_type[fields[field_no].type];
1526 }
1527 
1528 
cli_get_field_offset(cli_field_descriptor * fields,int field_no)1529 int cli_get_field_offset(cli_field_descriptor* fields, int field_no)
1530 {
1531     int offs = 0;
1532     int size = 0;
1533     for (int i = 0; i <= field_no; i++) {
1534         size = sizeof_type[fields[i].type];
1535         offs = DOALIGN(offs, alignof_type[fields[i].type]);
1536         offs += size;
1537     }
1538     return offs - size;
1539 }
1540 
cli_xml_export(int session,FILE * out)1541 int cli_xml_export(int session, FILE* out)
1542 {
1543     return cli_not_implemented;
1544 }
1545 
cli_xml_import(int session,FILE * in)1546 int cli_xml_import(int session, FILE* in)
1547 {
1548     return cli_not_implemented;
1549 }
1550 
cli_backup(int session,char const * file_name,int compactify)1551 int cli_backup(int session, char const* file_name, int compactify)
1552 {
1553     return cli_not_implemented;
1554 }
1555 
cli_schedule_backup(int session,char const * file_name,int period)1556 int cli_schedule_backup(int session, char const* file_name, int period)
1557 {
1558     return cli_not_implemented;
1559 }
1560 
cli_get_wrapping_rectangle(int session,char const * table,char const * field,cli_rectangle_t * rect)1561 int cli_get_wrapping_rectangle(int session, char const* table, char const* field, cli_rectangle_t* rect)
1562 {
1563     return cli_not_implemented;
1564 }
1565