1/****************** jsonudf C++ Program Source Code File (.CPP) ******************/
2/* PROGRAM NAME: jsonudf Version 1.7 */
3/* (C) Copyright to the author Olivier BERTRAND 2015-2018 */
4/* This program are the JSON User Defined Functions . */
5/*********************************************************************************/
6
7/*********************************************************************************/
8/* Include relevant sections of the MariaDB header file. */
9/*********************************************************************************/
10#include <my_global.h>
11#include <mysqld.h>
12#include <mysql.h>
13#include <sql_error.h>
14#include <stdio.h>
15
16#include "jsonudf.h"
17
18#if defined(UNIX) || defined(UNIV_LINUX)
19#define _O_RDONLY O_RDONLY
20#endif
21
22#define MEMFIX 4096
23#if defined(connect_EXPORTS)
24#define PUSH_WARNING(M) push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0, M)
25#else
26#define PUSH_WARNING(M) htrc(M)
27#endif
28#define M 7
29
30bool IsNum(PSZ s);
31char *NextChr(PSZ s, char sep);
32char *GetJsonNull(void);
33uint GetJsonGrpSize(void);
34static int IsJson(UDF_ARGS *args, uint i, bool b = false);
35static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i);
36static char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
37 unsigned long *res_length, char *is_null, char *error);
38static char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
39 unsigned long *res_length, char *is_null, char *error);
40static PJSON JsonNew(PGLOBAL g, JTYP type);
41static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp = NULL);
42static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len = 64);
43
44static uint JsonGrpSize = 10;
45
46/*********************************************************************************/
47/* SubAlloc a new JSNX class with protection against memory exhaustion. */
48/*********************************************************************************/
49static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len)
50{
51 PJSNX jsx;
52
53 try {
54 jsx = new(g) JSNX(g, jsp, type, len);
55 } catch (...) {
56 if (trace(1023))
57 htrc("%s\n", g->Message);
58
59 PUSH_WARNING(g->Message);
60 jsx = NULL;
61 } // end try/catch
62
63 return jsx;
64} /* end of JsnxNew */
65
66 /* ----------------------------------- JSNX ------------------------------------ */
67
68/*********************************************************************************/
69/* JSNX public constructor. */
70/*********************************************************************************/
71JSNX::JSNX(PGLOBAL g, PJSON row, int type, int len, int prec, my_bool wr)
72{
73 Row = row;
74 Jvalp = NULL;
75 Jpnp = NULL;
76 Jp = NULL;
77 Nodes = NULL;
78 Value = AllocateValue(g, type, len, prec);
79 MulVal = NULL;
80 Jpath = NULL;
81 Buf_Type = type;
82 Long = len;
83 Prec = prec;
84 Nod = 0;
85 Xnod = -1;
86 K = 0;
87 I = -1;
88 Imax = 9;
89 B = 0;
90 Xpd = false;
91 Parsed = false;
92 Found = false;
93 Wr = wr;
94 Jb = false;
95} // end of JSNX constructor
96
97/*********************************************************************************/
98/* SetJpath: set and parse the json path. */
99/*********************************************************************************/
100my_bool JSNX::SetJpath(PGLOBAL g, char *path, my_bool jb)
101{
102 // Check Value was allocated
103 if (!Value)
104 return true;
105
106 Value->SetNullable(true);
107 Jpath = path;
108
109 // Parse the json path
110 Parsed = false;
111 Nod = 0;
112 Jb = jb;
113 return ParseJpath(g);
114} // end of SetJpath
115
116/*********************************************************************************/
117/* Analyse array processing options. */
118/*********************************************************************************/
119my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
120{
121 int n = (int)strlen(p);
122 my_bool dg = true, b = false;
123 PJNODE jnp = &Nodes[i];
124
125 if (*p) {
126 if (p[n - 1] == ']') {
127 p[--n] = 0;
128 } else if (!IsNum(p)) {
129 // Wrong array specification
130 sprintf(g->Message, "Invalid array specification %s", p);
131 return true;
132 } // endif p
133
134 } else
135 b = true;
136
137 // To check whether a numeric Rank was specified
138 dg = IsNum(p);
139
140 if (!n) {
141 // Default specifications
142 if (jnp->Op != OP_EXP) {
143 if (Wr) {
144 // Force append
145 jnp->Rank = INT_MAX32;
146 jnp->Op = OP_LE;
147 } else if (Jb) {
148 // Return a Json item
149 jnp->Op = OP_XX;
150 } else if (b) {
151 // Return 1st value (B is the index base)
152 jnp->Rank = B;
153 jnp->Op = OP_LE;
154 } else if (!Value->IsTypeNum()) {
155 jnp->CncVal = AllocateValue(g, PlugDup(g, ", "), TYPE_STRING);
156 jnp->Op = OP_CNC;
157 } else
158 jnp->Op = OP_ADD;
159
160 } // endif OP
161
162 } else if (dg) {
163 // Return nth value
164 jnp->Rank = atoi(p) - B;
165 jnp->Op = OP_EQ;
166 } else if (Wr) {
167 sprintf(g->Message, "Invalid specification %s in a write path", p);
168 return true;
169 } else if (n == 1) {
170 // Set the Op value;
171 switch (*p) {
172 case '+': jnp->Op = OP_ADD; break;
173 case 'x': jnp->Op = OP_MULT; break;
174 case '>': jnp->Op = OP_MAX; break;
175 case '<': jnp->Op = OP_MIN; break;
176 case '!': jnp->Op = OP_SEP; break; // Average
177 case '#': jnp->Op = OP_NUM; break;
178 case '*': // Expand this array
179 strcpy(g->Message, "Expand not supported by this function");
180 return true;
181 default:
182 sprintf(g->Message, "Invalid function specification %c", *p);
183 return true;
184 } // endswitch *p
185
186 } else if (*p == '"' && p[n - 1] == '"') {
187 // This is a concat specification
188 jnp->Op = OP_CNC;
189
190 if (n > 2) {
191 // Set concat intermediate string
192 p[n - 1] = 0;
193
194 if (trace(1))
195 htrc("Concat string=%s\n", p + 1);
196
197 jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
198 } // endif n
199
200 } else {
201 strcpy(g->Message, "Wrong array specification");
202 return true;
203 } // endif's
204
205 // For calculated arrays, a local Value must be used
206 switch (jnp->Op) {
207 case OP_NUM:
208 jnp->Valp = AllocateValue(g, TYPE_INT);
209 break;
210 case OP_ADD:
211 case OP_MULT:
212 case OP_SEP:
213 if (!IsTypeChar(Buf_Type))
214 jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
215 else
216 jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
217
218 break;
219 case OP_MIN:
220 case OP_MAX:
221 jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
222 break;
223 case OP_CNC:
224 if (IsTypeChar(Buf_Type))
225 jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
226 else
227 jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
228
229 break;
230 default:
231 break;
232 } // endswitch Op
233
234 if (jnp->Valp)
235 MulVal = AllocateValue(g, jnp->Valp);
236
237 return false;
238} // end of SetArrayOptions
239
240/*********************************************************************************/
241/* Parse the eventual passed Jpath information. */
242/* This information can be specified in the Fieldfmt column option when */
243/* creating the table. It permits to indicate the position of the node */
244/* corresponding to that column. */
245/*********************************************************************************/
246my_bool JSNX::ParseJpath(PGLOBAL g)
247{
248 char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL;
249 int i;
250 my_bool a, mul = false;
251
252 if (Parsed)
253 return false; // Already done
254 else if (!Jpath)
255 // Jpath = Name;
256 return true;
257
258 if (trace(1))
259 htrc("ParseJpath %s\n", SVP(Jpath));
260
261 if (!(pbuf = PlgDBDup(g, Jpath)))
262 return true;
263
264 if (*pbuf == '$') pbuf++;
265 if (*pbuf == '.') pbuf++;
266 if (*pbuf == '[') p1 = pbuf++;
267
268 // Estimate the required number of nodes
269 for (i = 0, p = pbuf; (p = NextChr(p, '.')); i++, p++)
270 Nod++; // One path node found
271
272 if (!(Nodes = (PJNODE)PlgDBSubAlloc(g, NULL, (++Nod) * sizeof(JNODE))))
273 return true;
274
275 memset(Nodes, 0, (Nod)* sizeof(JNODE));
276
277 // Analyze the Jpath for this column
278 for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
279 a = (p1 != NULL);
280 p1 = strchr(p, '[');
281 p2 = strchr(p, '.');
282
283 if (!p2)
284 p2 = p1;
285 else if (p1) {
286 if (p1 < p2)
287 p2 = p1;
288 else if (p1 == p2 + 1)
289 *p2++ = 0; // Old syntax .[
290 else
291 p1 = NULL;
292
293 } // endif p1
294
295 if (p2)
296 *p2++ = 0;
297
298 // Jpath must be explicit
299 if (a || *p == 0 || *p == '[' || IsNum(p)) {
300 // Analyse intermediate array processing
301 if (SetArrayOptions(g, p, i, Nodes[i-1].Key))
302 return true;
303
304 } else if (*p == '*') {
305 if (Wr) {
306 sprintf(g->Message, "Invalid specification %c in a write path", *p);
307 return true;
308 } else // Return JSON
309 Nodes[i].Op = OP_XX;
310
311 } else {
312 Nodes[i].Key = p;
313 Nodes[i].Op = OP_EXIST;
314 } // endif's
315
316 } // endfor i, p
317
318 Nod = i;
319 MulVal = AllocateValue(g, Value);
320
321 if (trace(1))
322 for (i = 0; i < Nod; i++)
323 htrc("Node(%d) Key=%s Op=%d Rank=%d\n",
324 i, SVP(Nodes[i].Key), Nodes[i].Op, Nodes[i].Rank);
325
326 Parsed = true;
327 return false;
328} // end of ParseJpath
329
330/*********************************************************************************/
331/* MakeJson: Serialize the json item and set value to it. */
332/*********************************************************************************/
333PVAL JSNX::MakeJson(PGLOBAL g, PJSON jsp)
334{
335 if (Value->IsTypeNum()) {
336 strcpy(g->Message, "Cannot make Json for a numeric value");
337 Value->Reset();
338 } else if (jsp->GetType() != TYPE_JAR && jsp->GetType() != TYPE_JOB) {
339 strcpy(g->Message, "Target is not an array or object");
340 Value->Reset();
341 } else
342 Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
343
344 return Value;
345} // end of MakeJson
346
347/*********************************************************************************/
348/* SetValue: Set a value from a JVALUE contains. */
349/*********************************************************************************/
350void JSNX::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
351{
352 if (val) {
353 vp->SetNull(false);
354
355 if (Jb) {
356 vp->SetValue_psz(Serialize(g, val->GetJsp(), NULL, 0));
357 } else switch (val->GetValType()) {
358 case TYPE_STRG:
359 case TYPE_INTG:
360 case TYPE_BINT:
361 case TYPE_DBL:
362 vp->SetValue_pval(val->GetValue());
363 break;
364 case TYPE_BOOL:
365 if (vp->IsTypeNum())
366 vp->SetValue(val->GetInteger() ? 1 : 0);
367 else
368 vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
369
370 break;
371 case TYPE_JAR:
372 SetJsonValue(g, vp, val->GetArray()->GetValue(0), n);
373 break;
374 case TYPE_JOB:
375// if (!vp->IsTypeNum() || !Strict) {
376 vp->SetValue_psz(val->GetObject()->GetText(g, NULL));
377 break;
378// } // endif Type
379
380 case TYPE_NULL:
381 vp->SetNull(true);
382 default:
383 vp->Reset();
384 } // endswitch Type
385
386 } else {
387 vp->SetNull(true);
388 vp->Reset();
389 } // endif val
390
391} // end of SetJsonValue
392
393/*********************************************************************************/
394/* GetJson: */
395/*********************************************************************************/
396PJVAL JSNX::GetJson(PGLOBAL g)
397{
398 return GetRowValue(g, Row, 0);
399} // end of GetJson
400
401/*********************************************************************************/
402/* ReadValue: */
403/*********************************************************************************/
404void JSNX::ReadValue(PGLOBAL g)
405{
406 Value->SetValue_pval(GetColumnValue(g, Row, 0));
407} // end of ReadValue
408
409/*********************************************************************************/
410/* GetColumnValue: */
411/*********************************************************************************/
412PVAL JSNX::GetColumnValue(PGLOBAL g, PJSON row, int i)
413{
414 int n = Nod - 1;
415 PJVAL val = NULL;
416
417 val = GetRowValue(g, row, i);
418 SetJsonValue(g, Value, val, n);
419 return Value;
420} // end of GetColumnValue
421
422/*********************************************************************************/
423/* GetRowValue: */
424/*********************************************************************************/
425PJVAL JSNX::GetRowValue(PGLOBAL g, PJSON row, int i, my_bool b)
426{
427 my_bool expd = false;
428 PJAR arp;
429 PJVAL val = NULL;
430
431 for (; i < Nod && row; i++) {
432 if (Nodes[i].Op == OP_NUM) {
433 Value->SetValue(row->GetType() == TYPE_JAR ? row->size() : 1);
434 val = new(g) JVALUE(g, Value);
435 return val;
436 } else if (Nodes[i].Op == OP_XX) {
437 Jb = b;
438 return new(g)JVALUE(row);
439 } else switch (row->GetType()) {
440 case TYPE_JOB:
441 if (!Nodes[i].Key) {
442 // Expected Array was not there
443 if (Nodes[i].Op == OP_LE) {
444 if (i < Nod-1)
445 continue;
446 else
447 val = new(g)JVALUE(row);
448
449 } else {
450 strcpy(g->Message, "Unexpected object");
451 val = NULL;
452 } //endif Op
453
454 } else
455 val = ((PJOB)row)->GetValue(Nodes[i].Key);
456
457 break;
458 case TYPE_JAR:
459 arp = (PJAR)row;
460
461 if (!Nodes[i].Key) {
462 if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
463 val = arp->GetValue(Nodes[i].Rank);
464 else if (Nodes[i].Op == OP_EXP)
465 return (PJVAL)ExpandArray(g, arp, i);
466 else
467 return new(g) JVALUE(g, CalculateArray(g, arp, i));
468
469 } else {
470 // Unexpected array, unwrap it as [0]
471 val = arp->GetValue(0);
472 i--;
473 } // endif's
474
475 break;
476 case TYPE_JVAL:
477 val = (PJVAL)row;
478 break;
479 default:
480 sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
481 val = NULL;
482 } // endswitch Type
483
484 if (i < Nod-1)
485 if (!(row = (val) ? val->GetJsp() : NULL))
486 val = NULL;
487// row = (val) ? val->GetJson() : NULL;
488
489 } // endfor i
490
491 // SetJsonValue(g, Value, val, n);
492 return val;
493} // end of GetRowValue
494
495/*********************************************************************************/
496/* ExpandArray: */
497/*********************************************************************************/
498PVAL JSNX::ExpandArray(PGLOBAL g, PJAR arp, int n)
499{
500 strcpy(g->Message, "Expand cannot be done by this function");
501 return NULL;
502} // end of ExpandArray
503
504/*********************************************************************************/
505/* CalculateArray: */
506/*********************************************************************************/
507PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
508{
509 int i, ars = arp->size(), nv = 0;
510 bool err;
511 OPVAL op = Nodes[n].Op;
512 PVAL val[2], vp = Nodes[n].Valp;
513 PJVAL jvrp, jvp;
514 JVALUE jval;
515
516 vp->Reset();
517
518 if (trace(1))
519 htrc("CalculateArray size=%d op=%d\n", ars, op);
520
521 for (i = 0; i < ars; i++) {
522 jvrp = arp->GetValue(i);
523
524 if (trace(1))
525 htrc("i=%d nv=%d\n", i, nv);
526
527 if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) {
528 if (jvrp->IsNull()) {
529 jvrp->Value = AllocateValue(g, GetJsonNull(), TYPE_STRING);
530 jvp = jvrp;
531 } else if (n < Nod - 1 && jvrp->GetJson()) {
532 jval.SetValue(GetColumnValue(g, jvrp->GetJson(), n + 1));
533 jvp = &jval;
534 } else
535 jvp = jvrp;
536
537 if (trace(1))
538 htrc("jvp=%s null=%d\n",
539 jvp->GetString(g), jvp->IsNull() ? 1 : 0);
540
541 if (!nv++) {
542 SetJsonValue(g, vp, jvp, n);
543 continue;
544 } else
545 SetJsonValue(g, MulVal, jvp, n);
546
547 if (!MulVal->IsNull()) {
548 switch (op) {
549 case OP_CNC:
550 if (Nodes[n].CncVal) {
551 val[0] = Nodes[n].CncVal;
552 err = vp->Compute(g, val, 1, op);
553 } // endif CncVal
554
555 val[0] = MulVal;
556 err = vp->Compute(g, val, 1, op);
557 break;
558// case OP_NUM:
559 case OP_SEP:
560 val[0] = Nodes[n].Valp;
561 val[1] = MulVal;
562 err = vp->Compute(g, val, 2, OP_ADD);
563 break;
564 default:
565 val[0] = Nodes[n].Valp;
566 val[1] = MulVal;
567 err = vp->Compute(g, val, 2, op);
568 } // endswitch Op
569
570 if (err)
571 vp->Reset();
572
573 if (trace(1)) {
574 char buf(32);
575
576 htrc("vp='%s' err=%d\n",
577 vp->GetCharString(&buf), err ? 1 : 0);
578 } // endif trace
579
580 } // endif Zero
581
582 } // endif jvrp
583
584 } // endfor i
585
586 if (op == OP_SEP) {
587 // Calculate average
588 MulVal->SetValue(nv);
589 val[0] = vp;
590 val[1] = MulVal;
591
592 if (vp->Compute(g, val, 2, OP_DIV))
593 vp->Reset();
594
595 } // endif Op
596
597 return vp;
598} // end of CalculateArray
599
600/*********************************************************************************/
601/* CheckPath: Checks whether the path exists in the document. */
602/*********************************************************************************/
603my_bool JSNX::CheckPath(PGLOBAL g)
604{
605 PJVAL val= NULL;
606 PJSON row = Row;
607
608 for (int i = 0; i < Nod && row; i++) {
609 val = NULL;
610
611 if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
612 } else switch (row->GetType()) {
613 case TYPE_JOB:
614 if (Nodes[i].Key)
615 val = ((PJOB)row)->GetValue(Nodes[i].Key);
616
617 break;
618 case TYPE_JAR:
619 if (!Nodes[i].Key)
620 if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
621 val = ((PJAR)row)->GetValue(Nodes[i].Rank);
622
623 break;
624 case TYPE_JVAL:
625 val = (PJVAL)row;
626 break;
627 default:
628 sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
629 } // endswitch Type
630
631 if (i < Nod-1)
632 if (!(row = (val) ? val->GetJsp() : NULL))
633 val = NULL;
634
635 } // endfor i
636
637 return (val != NULL);
638} // end of CheckPath
639
640/***********************************************************************/
641/* GetRow: Set the complete path of the object to be set. */
642/***********************************************************************/
643PJSON JSNX::GetRow(PGLOBAL g)
644{
645 PJVAL val = NULL;
646 PJAR arp;
647 PJSON nwr, row = Row;
648
649 for (int i = 0; i < Nod - 1 && row; i++) {
650 if (Nodes[i].Op == OP_XX)
651 break;
652 else switch (row->GetType()) {
653 case TYPE_JOB:
654 if (!Nodes[i].Key)
655 // Expected Array was not there, wrap the value
656 continue;
657
658 val = ((PJOB)row)->GetValue(Nodes[i].Key);
659 break;
660 case TYPE_JAR:
661 arp = (PJAR)row;
662
663 if (!Nodes[i].Key) {
664 if (Nodes[i].Op == OP_EQ)
665 val = arp->GetValue(Nodes[i].Rank);
666 else
667 val = arp->GetValue(Nodes[i].Rx);
668
669 } else {
670 // Unexpected array, unwrap it as [0]
671 val = arp->GetValue(0);
672 i--;
673 } // endif Nodes
674
675 break;
676 case TYPE_JVAL:
677 val = (PJVAL)row;
678 break;
679 default:
680 sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
681 val = NULL;
682 } // endswitch Type
683
684 if (val) {
685 row = val->GetJson();
686 } else {
687 // Construct missing objects
688 for (i++; row && i < Nod; i++) {
689 if (Nodes[i].Op == OP_XX)
690 break;
691 else if (!Nodes[i].Key)
692 // Construct intermediate array
693 nwr = new(g)JARRAY;
694 else
695 nwr = new(g)JOBJECT;
696
697 if (row->GetType() == TYPE_JOB) {
698 ((PJOB)row)->SetValue(g, new(g)JVALUE(nwr), Nodes[i-1].Key);
699 } else if (row->GetType() == TYPE_JAR) {
700 ((PJAR)row)->AddValue(g, new(g)JVALUE(nwr));
701 ((PJAR)row)->InitArray(g);
702 } else {
703 strcpy(g->Message, "Wrong type when writing new row");
704 nwr = NULL;
705 } // endif's
706
707 row = nwr;
708 } // endfor i
709
710 break;
711 } // endelse
712
713 } // endfor i
714
715 return row;
716} // end of GetRow
717
718/***********************************************************************/
719/* WriteValue: */
720/***********************************************************************/
721my_bool JSNX::WriteValue(PGLOBAL g, PJVAL jvalp)
722{
723 PJOB objp = NULL;
724 PJAR arp = NULL;
725 PJVAL jvp = NULL;
726 PJSON row = GetRow(g);
727
728 if (!row)
729 return true;
730
731 switch (row->GetType()) {
732 case TYPE_JOB: objp = (PJOB)row; break;
733 case TYPE_JAR: arp = (PJAR)row; break;
734 case TYPE_JVAL: jvp = (PJVAL)row; break;
735 default:
736 strcpy(g->Message, "Invalid target type");
737 return true;
738 } // endswitch Type
739
740 if (arp) {
741 if (!Nodes[Nod-1].Key) {
742 if (Nodes[Nod-1].Op == OP_EQ)
743 arp->SetValue(g, jvalp, Nodes[Nod-1].Rank);
744 else
745 arp->AddValue(g, jvalp);
746
747 arp->InitArray(g);
748 } // endif Key
749
750 } else if (objp) {
751 if (Nodes[Nod-1].Key)
752 objp->SetValue(g, jvalp, Nodes[Nod-1].Key);
753
754 } else if (jvp)
755 jvp->SetValue(jvalp);
756
757 return false;
758} // end of WriteValue
759
760/*********************************************************************************/
761/* Locate a value in a JSON tree: */
762/*********************************************************************************/
763PSZ JSNX::Locate(PGLOBAL g, PJSON jsp, PJVAL jvp, int k)
764{
765 PSZ str = NULL;
766 my_bool b = false, err = true;
767
768 g->Message[0] = 0;
769
770 if (!jsp) {
771 strcpy(g->Message, "Null json tree");
772 return NULL;
773 } // endif jsp
774
775 try {
776 // Write to the path string
777 Jp = new(g) JOUTSTR(g);
778 Jp->WriteChr('$');
779 Jvalp = jvp;
780 K = k;
781
782 switch (jsp->GetType()) {
783 case TYPE_JAR:
784 err = LocateArray((PJAR)jsp);
785 break;
786 case TYPE_JOB:
787 err = LocateObject((PJOB)jsp);
788 break;
789 case TYPE_JVAL:
790 err = LocateValue((PJVAL)jsp);
791 break;
792 default:
793 err = true;
794 } // endswitch Type
795
796 if (err) {
797 if (!g->Message[0])
798 strcpy(g->Message, "Invalid json tree");
799
800 } else if (Found) {
801 Jp->WriteChr('\0');
802 PlugSubAlloc(g, NULL, Jp->N);
803 str = Jp->Strp;
804 } // endif's
805
806 } catch (int n) {
807 if (trace(1))
808 htrc("Exception %d: %s\n", n, g->Message);
809
810 PUSH_WARNING(g->Message);
811 } catch (const char *msg) {
812 strcpy(g->Message, msg);
813 } // end catch
814
815 return str;
816} // end of Locate
817
818/*********************************************************************************/
819/* Locate in a JSON Array. */
820/*********************************************************************************/
821my_bool JSNX::LocateArray(PJAR jarp)
822{
823 char s[16];
824 size_t m = Jp->N;
825
826 for (int i = 0; i < jarp->size() && !Found; i++) {
827 Jp->N = m;
828 sprintf(s, "[%d]", i + B);
829
830 if (Jp->WriteStr(s))
831 return true;
832
833 if (LocateValue(jarp->GetValue(i)))
834 return true;
835
836 } // endfor i
837
838 return false;
839} // end of LocateArray
840
841/*********************************************************************************/
842/* Locate in a JSON Object. */
843/*********************************************************************************/
844my_bool JSNX::LocateObject(PJOB jobp)
845{
846 size_t m;
847
848 if (Jp->WriteChr('.'))
849 return true;
850
851 m = Jp->N;
852
853 for (PJPR pair = jobp->First; pair && !Found; pair = pair->Next) {
854 Jp->N = m;
855
856 if (Jp->WriteStr(pair->Key))
857 return true;
858
859 if (LocateValue(pair->Val))
860 return true;
861
862 } // endfor i
863
864 return false;
865} // end of LocateObject
866
867/*********************************************************************************/
868/* Locate a JSON Value. */
869/*********************************************************************************/
870my_bool JSNX::LocateValue(PJVAL jvp)
871{
872 if (CompareTree(Jvalp, jvp))
873 Found = (--K == 0);
874 else if (jvp->GetArray())
875 return LocateArray(jvp->GetArray());
876 else if (jvp->GetObject())
877 return LocateObject(jvp->GetObject());
878
879 return false;
880} // end of LocateValue
881
882/*********************************************************************************/
883/* Locate all occurrences of a value in a JSON tree: */
884/*********************************************************************************/
885PSZ JSNX::LocateAll(PGLOBAL g, PJSON jsp, PJVAL jvp, int mx)
886{
887 PSZ str = NULL;
888 my_bool b = false, err = true;
889 PJPN jnp;
890
891 if (!jsp) {
892 strcpy(g->Message, "Null json tree");
893 return NULL;
894 } // endif jsp
895
896 try {
897 jnp = (PJPN)PlugSubAlloc(g, NULL, sizeof(JPN) * mx);
898 memset(jnp, 0, sizeof(JPN) * mx);
899 g->Message[0] = 0;
900
901 // Write to the path string
902 Jp = new(g)JOUTSTR(g);
903 Jvalp = jvp;
904 Imax = mx - 1;
905 Jpnp = jnp;
906 Jp->WriteChr('[');
907
908 switch (jsp->GetType()) {
909 case TYPE_JAR:
910 err = LocateArrayAll((PJAR)jsp);
911 break;
912 case TYPE_JOB:
913 err = LocateObjectAll((PJOB)jsp);
914 break;
915 case TYPE_JVAL:
916 err = LocateValueAll((PJVAL)jsp);
917 break;
918 default:
919 err = true;
920 } // endswitch Type
921
922 if (!err) {
923 if (Jp->N > 1)
924 Jp->N--;
925
926 Jp->WriteChr(']');
927 Jp->WriteChr('\0');
928 PlugSubAlloc(g, NULL, Jp->N);
929 str = Jp->Strp;
930 } else if (!g->Message[0])
931 strcpy(g->Message, "Invalid json tree");
932
933 } catch (int n) {
934 if (trace(1))
935 htrc("Exception %d: %s\n", n, g->Message);
936
937 PUSH_WARNING(g->Message);
938 } catch (const char *msg) {
939 strcpy(g->Message, msg);
940 } // end catch
941
942 return str;
943} // end of LocateAll
944
945/*********************************************************************************/
946/* Locate in a JSON Array. */
947/*********************************************************************************/
948my_bool JSNX::LocateArrayAll(PJAR jarp)
949{
950 if (I < Imax) {
951 Jpnp[++I].Type = TYPE_JAR;
952
953 for (int i = 0; i < jarp->size(); i++) {
954 Jpnp[I].N = i;
955
956 if (LocateValueAll(jarp->GetValue(i)))
957 return true;
958
959 } // endfor i
960
961 I--;
962 } // endif I
963
964 return false;
965} // end of LocateArrayAll
966
967/*********************************************************************************/
968/* Locate in a JSON Object. */
969/*********************************************************************************/
970my_bool JSNX::LocateObjectAll(PJOB jobp)
971{
972 if (I < Imax) {
973 Jpnp[++I].Type = TYPE_JOB;
974
975 for (PJPR pair = jobp->First; pair; pair = pair->Next) {
976 Jpnp[I].Key = pair->Key;
977
978 if (LocateValueAll(pair->Val))
979 return true;
980
981 } // endfor i
982
983 I--;
984 } // endif I
985
986 return false;
987} // end of LocateObjectAll
988
989/*********************************************************************************/
990/* Locate a JSON Value. */
991/*********************************************************************************/
992my_bool JSNX::LocateValueAll(PJVAL jvp)
993{
994 if (CompareTree(Jvalp, jvp))
995 return AddPath();
996 else if (jvp->GetArray())
997 return LocateArrayAll(jvp->GetArray());
998 else if (jvp->GetObject())
999 return LocateObjectAll(jvp->GetObject());
1000
1001 return false;
1002} // end of LocateValueAll
1003
1004/*********************************************************************************/
1005/* Compare two JSON trees. */
1006/*********************************************************************************/
1007my_bool JSNX::CompareTree(PJSON jp1, PJSON jp2)
1008{
1009 if (!jp1 || !jp2 || jp1->GetType() != jp2->GetType()
1010 || jp1->size() != jp2->size())
1011 return false;
1012
1013 my_bool found = true;
1014
1015 if (jp1->GetType() == TYPE_JVAL) {
1016 PVAL v1 = jp1->GetValue(), v2 = jp2->GetValue();
1017
1018 if (v1 && v2) {
1019 if (v1->GetType() == v2->GetType())
1020 found = !v1->CompareValue(v2);
1021 else
1022 found = false;
1023
1024 } else
1025 found = CompareTree(jp1->GetJsp(), jp2->GetJsp());
1026
1027 } else if (jp1->GetType() == TYPE_JAR) {
1028 for (int i = 0; found && i < jp1->size(); i++)
1029 found = (CompareTree(jp1->GetValue(i), jp2->GetValue(i)));
1030
1031 } else if (jp1->GetType() == TYPE_JOB) {
1032 PJPR p1 = jp1->GetFirst(), p2 = jp2->GetFirst();
1033
1034 for (; found && p1 && p2; p1 = p1->Next, p2 = p2->Next)
1035 found = CompareTree(p1->Val, p2->Val);
1036
1037 } else
1038 found = false;
1039
1040 return found;
1041} // end of CompareTree
1042
1043/*********************************************************************************/
1044/* Add the found path to the list. */
1045/*********************************************************************************/
1046my_bool JSNX::AddPath(void)
1047{
1048 char s[16];
1049
1050 if (Jp->WriteStr("\"$"))
1051 return true;
1052
1053 for (int i = 0; i <= I; i++) {
1054 if (Jpnp[i].Type == TYPE_JAR) {
1055 sprintf(s, "[%d]", Jpnp[i].N + B);
1056
1057 if (Jp->WriteStr(s))
1058 return true;
1059
1060 } else {
1061 if (Jp->WriteChr('.'))
1062 return true;
1063
1064 if (Jp->WriteStr(Jpnp[i].Key))
1065 return true;
1066
1067 } // endif's
1068
1069 } // endfor i
1070
1071 if (Jp->WriteStr("\","))
1072 return true;
1073
1074 return false;
1075} // end of AddPath
1076
1077/* --------------------------------- JSON UDF ---------------------------------- */
1078
1079// BSON size should be equal on Linux and Windows
1080#define BMX 255
1081typedef struct BSON *PBSON;
1082
1083/*********************************************************************************/
1084/* Structure used to return binary json. */
1085/*********************************************************************************/
1086struct BSON {
1087 char Msg[BMX + 1];
1088 char *Filename;
1089 PGLOBAL G;
1090 int Pretty;
1091 ulong Reslen;
1092 my_bool Changed;
1093 PJSON Top;
1094 PJSON Jsp;
1095 PBSON Bsp;
1096}; // end of struct BSON
1097
1098/*********************************************************************************/
1099/* Allocate and initialize a BSON structure. */
1100/*********************************************************************************/
1101static PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp)
1102{
1103 PBSON bsp = (PBSON)PlgDBSubAlloc(g, NULL, sizeof(BSON));
1104
1105 if (bsp) {
1106 strcpy(bsp->Msg, "Binary Json");
1107 bsp->Msg[BMX] = 0;
1108 bsp->Filename = NULL;
1109 bsp->G = g;
1110 bsp->Pretty = 2;
1111 bsp->Reslen = len;
1112 bsp->Changed = false;
1113 bsp->Top = bsp->Jsp = jsp;
1114 bsp->Bsp = (IsJson(args, 0) == 3) ? (PBSON)args->args[0] : NULL;
1115 } else
1116 PUSH_WARNING(g->Message);
1117
1118 return bsp;
1119} /* end of JbinAlloc */
1120
1121/*********************************************************************************/
1122/* Set the BSON chain as changed. */
1123/*********************************************************************************/
1124static void SetChanged(PBSON bsp)
1125{
1126 if (bsp->Bsp)
1127 SetChanged(bsp->Bsp);
1128
1129 bsp->Changed = true;
1130} /* end of SetChanged */
1131
1132/*********************************************************************************/
1133/* Replaces GetJsonGrpSize not usable when CONNECT is not installed. */
1134/*********************************************************************************/
1135static uint GetJsonGroupSize(void)
1136{
1137 return (JsonGrpSize) ? JsonGrpSize : GetJsonGrpSize();
1138} // end of GetJsonGroupSize
1139
1140/*********************************************************************************/
1141/* Program for SubSet re-initialization of the memory pool. */
1142/*********************************************************************************/
1143static my_bool JsonSubSet(PGLOBAL g)
1144{
1145 PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
1146
1147 pph->To_Free = (OFFSET)((g->Createas) ? g->Createas : sizeof(POOLHEADER));
1148 pph->FreeBlk = g->Sarea_Size - pph->To_Free;
1149 return FALSE;
1150} /* end of JsonSubSet */
1151
1152/*********************************************************************************/
1153/* Program for saving the status of the memory pools. */
1154/*********************************************************************************/
1155inline void JsonMemSave(PGLOBAL g)
1156{
1157 g->Createas = (int)((PPOOLHEADER)g->Sarea)->To_Free;
1158} /* end of JsonMemSave */
1159
1160/*********************************************************************************/
1161/* Program for freeing the memory pools. */
1162/*********************************************************************************/
1163inline void JsonFreeMem(PGLOBAL g)
1164{
1165 g->Activityp = NULL;
1166 PlugExit(g);
1167} /* end of JsonFreeMem */
1168
1169/*********************************************************************************/
1170/* SubAlloc a new JSON item with protection against memory exhaustion. */
1171/*********************************************************************************/
1172static PJSON JsonNew(PGLOBAL g, JTYP type)
1173{
1174 PJSON jsp = NULL;
1175
1176 try {
1177 switch (type) {
1178 case TYPE_JAR:
1179 jsp = new(g) JARRAY;
1180 break;
1181 case TYPE_JOB:
1182 jsp = new(g) JOBJECT;
1183 break;
1184 default:
1185 break;
1186 } // endswitch type
1187
1188 } catch (...) {
1189 if (trace(1023))
1190 htrc("%s\n", g->Message);
1191
1192 PUSH_WARNING(g->Message);
1193 } // end try/catch
1194
1195 return jsp;
1196} /* end of JsonNew */
1197
1198/*********************************************************************************/
1199/* SubAlloc a new JValue with protection against memory exhaustion. */
1200/*********************************************************************************/
1201static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp)
1202{
1203 PJVAL jvp = NULL;
1204
1205 try {
1206 if (!vp)
1207 jvp = new (g) JVALUE;
1208 else switch (type) {
1209 case TYPE_JSON:
1210 case TYPE_JVAL:
1211 case TYPE_JAR:
1212 case TYPE_JOB:
1213 jvp = new(g) JVALUE((PJSON)vp);
1214 break;
1215 case TYPE_VAL:
1216 jvp = new(g) JVALUE(g, (PVAL)vp);
1217 break;
1218 case TYPE_STRG:
1219 jvp = new(g) JVALUE(g, (PCSZ)vp);
1220 break;
1221 default:
1222 break;
1223 } // endswitch type
1224
1225 } catch (...) {
1226 if (trace(1023))
1227 htrc("%s\n", g->Message);
1228
1229 PUSH_WARNING(g->Message);
1230 } // end try/catch
1231
1232 return jvp;
1233} /* end of JsonNew */
1234
1235/*********************************************************************************/
1236/* Allocate and initialise the memory area. */
1237/*********************************************************************************/
1238static my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args,
1239 char *message, my_bool mbn,
1240 unsigned long reslen, unsigned long memlen,
1241 unsigned long more = 0)
1242{
1243 PGLOBAL g = PlugInit(NULL, memlen + more + 500); // +500 to avoid CheckMem
1244
1245 if (!g) {
1246 strcpy(message, "Allocation error");
1247 return true;
1248 } else if (g->Sarea_Size == 0) {
1249 strcpy(message, g->Message);
1250 PlugExit(g);
1251 return true;
1252 } // endif g
1253
1254 g->Mrr = (args->arg_count && args->args[0]) ? 1 : 0;
1255 g->More = more;
1256 initid->maybe_null = mbn;
1257 initid->max_length = reslen;
1258 initid->ptr = (char*)g;
1259 return false;
1260} // end of JsonInit
1261
1262/*********************************************************************************/
1263/* Check if a path was specified and set jvp according to it. */
1264/*********************************************************************************/
1265static my_bool CheckPath(PGLOBAL g, UDF_ARGS *args, PJSON jsp, PJVAL& jvp, int n)
1266{
1267 for (uint i = n; i < args->arg_count; i++)
1268 if (args->arg_type[i] == STRING_RESULT && args->args[i]) {
1269 // A path to a subset of the json tree is given
1270 char *path = MakePSZ(g, args, i);
1271
1272 if (path) {
1273 PJSNX jsx = new(g)JSNX(g, jsp, TYPE_STRING);
1274
1275 if (jsx->SetJpath(g, path))
1276 return true;
1277
1278 if (!(jvp = jsx->GetJson(g))) {
1279 sprintf(g->Message, "No sub-item at '%s'", path);
1280 return true;
1281 } // endif jvp
1282
1283 } else {
1284 strcpy(g->Message, "Path argument is null");
1285 return true;
1286 } // endif path
1287
1288 break;
1289 } // endif type
1290
1291 return false;
1292} // end of CheckPath
1293
1294/*********************************************************************************/
1295/* Make the result according to the first argument type. */
1296/*********************************************************************************/
1297static char *MakeResult(PGLOBAL g, UDF_ARGS *args, PJSON top, uint n = 2)
1298{
1299 char *str;
1300
1301 if (IsJson(args, 0) == 2) {
1302 // Make the change in the json file
1303 int pretty = 2;
1304
1305 for (uint i = n; i < args->arg_count; i++)
1306 if (args->arg_type[i] == INT_RESULT) {
1307 pretty = (int)*(longlong*)args->args[i];
1308 break;
1309 } // endif type
1310
1311 if (!Serialize(g, top, MakePSZ(g, args, 0), pretty))
1312 PUSH_WARNING(g->Message);
1313
1314 str = NULL;
1315 } else if (IsJson(args, 0) == 3) {
1316 PBSON bsp = (PBSON)args->args[0];
1317
1318 if (bsp->Filename) {
1319 // Make the change in the json file
1320 if (!Serialize(g, top, bsp->Filename, bsp->Pretty))
1321 PUSH_WARNING(g->Message);
1322
1323 str = bsp->Filename;
1324 } else if (!(str = Serialize(g, top, NULL, 0)))
1325 PUSH_WARNING(g->Message);
1326
1327 SetChanged(bsp);
1328 } else if (!(str = Serialize(g, top, NULL, 0)))
1329 PUSH_WARNING(g->Message);
1330
1331 return str;
1332} // end of MakeResult
1333
1334/*********************************************************************************/
1335/* Make the binary result according to the first argument type. */
1336/*********************************************************************************/
1337static PBSON MakeBinResult(PGLOBAL g, UDF_ARGS *args, PJSON top, ulong len, int n = 2)
1338{
1339 PBSON bsnp = JbinAlloc(g, args, len, top);
1340
1341 if (!bsnp)
1342 return NULL;
1343
1344 if (IsJson(args, 0) == 2) {
1345 int pretty = 0;
1346
1347 for (uint i = n; i < args->arg_count; i++)
1348 if (args->arg_type[i] == INT_RESULT) {
1349 pretty = (int)*(longlong*)args->args[i];
1350 break;
1351 } // endif type
1352
1353 bsnp->Pretty = pretty;
1354
1355 if (bsnp->Filename = (char*)args->args[0]) {
1356 bsnp->Filename = MakePSZ(g, args, 0);
1357 strncpy(bsnp->Msg, bsnp->Filename, BMX);
1358 } else
1359 strncpy(bsnp->Msg, "null filename", BMX);
1360
1361 } else if (IsJson(args, 0) == 3) {
1362 PBSON bsp = (PBSON)args->args[0];
1363
1364 if (bsp->Filename) {
1365 bsnp->Filename = bsp->Filename;
1366 strncpy(bsnp->Msg, bsp->Filename, BMX);
1367 bsnp->Pretty = bsp->Pretty;
1368 } else
1369 strcpy(bsnp->Msg, "Json Binary item");
1370
1371 } else
1372 strcpy(bsnp->Msg, "Json Binary item");
1373
1374 return bsnp;
1375} // end of MakeBinResult
1376
1377/*********************************************************************************/
1378/* Returns a pointer to the first integer argument found from the nth argument. */
1379/*********************************************************************************/
1380static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n)
1381{
1382 int *x = NULL;
1383
1384 for (uint i = n; i < args->arg_count; i++)
1385 if (args->arg_type[i] == INT_RESULT) {
1386 if (args->args[i]) {
1387 if ((x = (int*)PlgDBSubAlloc(g, NULL, sizeof(int))))
1388 *x = (int)*(longlong*)args->args[i];
1389 else
1390 PUSH_WARNING(g->Message);
1391
1392 } // endif args
1393
1394 n = i + 1;
1395 break;
1396 } // endif arg_type
1397
1398 return x;
1399} // end of GetIntArgPtr
1400
1401/*********************************************************************************/
1402/* Returns not 0 if the argument is a JSON item or file name. */
1403/*********************************************************************************/
1404static int IsJson(UDF_ARGS *args, uint i, bool b)
1405{
1406 int n = 0;
1407
1408 if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) {
1409 } else if (!strnicmp(args->attributes[i], "Json_", 5)) {
1410 if (!args->args[i] || strchr("[{ \t\r\n", *args->args[i]))
1411 n = 1; // arg should be is a json item
1412 else
1413 n = 2; // A file name may have been returned
1414
1415 } else if (!strnicmp(args->attributes[i], "Jbin_", 5)) {
1416 if (args->lengths[i] == sizeof(BSON))
1417 n = 3; // arg is a binary json item
1418 else
1419 n = 2; // A file name may have been returned
1420
1421 } else if (!strnicmp(args->attributes[i], "Jfile_", 6)) {
1422 n = 2; // arg is a json file name
1423 } else if (b) {
1424 char *sap;
1425 PGLOBAL g = PlugInit(NULL, args->lengths[i] * M + 1024);
1426
1427 JsonSubSet(g);
1428 sap = MakePSZ(g, args, i);
1429
1430 if (ParseJson(g, sap, strlen(sap)))
1431 n = 4;
1432
1433 JsonFreeMem(g);
1434 } // endif's
1435
1436 return n;
1437} // end of IsJson
1438
1439/*********************************************************************************/
1440/* GetMemPtr: returns the memory pointer used by this argument. */
1441/*********************************************************************************/
1442static PGLOBAL GetMemPtr(PGLOBAL g, UDF_ARGS *args, uint i)
1443{
1444 return (IsJson(args, i) == 3) ? ((PBSON)args->args[i])->G : g;
1445} // end of GetMemPtr
1446
1447/*********************************************************************************/
1448/* GetFileLength: returns file size in number of bytes. */
1449/*********************************************************************************/
1450static long GetFileLength(char *fn)
1451{
1452 int h;
1453 long len;
1454
1455 h= open(fn, _O_RDONLY);
1456
1457 if (h != -1) {
1458 if ((len = _filelength(h)) < 0)
1459 len = 0;
1460
1461 close(h);
1462 } else
1463 len = 0;
1464
1465 return len;
1466} // end of GetFileLength
1467
1468/*********************************************************************************/
1469/* Calculate the reslen and memlen needed by a function. */
1470/*********************************************************************************/
1471static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
1472 unsigned long& reslen, unsigned long& memlen,
1473 my_bool mod = false)
1474{
1475 char fn[_MAX_PATH];
1476 unsigned long i, k, m, n;
1477 long fl = 0, j = -1;
1478
1479 reslen = args->arg_count + 2;
1480
1481 // Calculate the result max length
1482 for (i = 0; i < args->arg_count; i++) {
1483 n = IsJson(args, i);
1484
1485 if (obj) {
1486 if (!(k = args->attribute_lengths[i]))
1487 k = strlen(args->attributes[i]);
1488
1489 reslen += (k + 3); // For quotes and :
1490 } // endif obj
1491
1492 switch (args->arg_type[i]) {
1493 case STRING_RESULT:
1494 if (n == 2 && args->args[i]) {
1495 if (!mod) {
1496 m = MY_MIN(args->lengths[i], sizeof(fn) - 1);
1497 memcpy(fn, args->args[i], m);
1498 fn[m] = 0;
1499 j = i;
1500 fl = GetFileLength(fn);
1501 reslen += fl;
1502 } else
1503 reslen += args->lengths[i];
1504
1505 } else if (n == 3 && args->args[i])
1506 reslen += ((PBSON)args->args[i])->Reslen;
1507 else if (n == 1)
1508 reslen += args->lengths[i];
1509 else
1510 reslen += (args->lengths[i] + 1) * 2; // Pessimistic !
1511
1512 break;
1513 case INT_RESULT:
1514 reslen += 20;
1515 break;
1516 case REAL_RESULT:
1517 reslen += 31;
1518 break;
1519 case DECIMAL_RESULT:
1520 reslen += (args->lengths[i] + 7); // 6 decimals
1521 break;
1522 case TIME_RESULT:
1523 case ROW_RESULT:
1524 default:
1525 // What should we do here ?
1526 break;
1527 } // endswitch arg_type
1528
1529 } // endfor i
1530
1531 // Calculate the amount of memory needed
1532 memlen = MEMFIX + sizeof(JOUTSTR) + reslen;
1533
1534 for (i = 0; i < args->arg_count; i++) {
1535 n = IsJson(args, i);
1536 memlen += (args->lengths[i] + sizeof(JVALUE));
1537
1538 if (obj) {
1539 if (!(k = args->attribute_lengths[i]))
1540 k = strlen(args->attributes[i]);
1541
1542 memlen += (k + sizeof(JOBJECT) + sizeof(JPAIR));
1543 } else
1544 memlen += sizeof(JARRAY);
1545
1546 switch (args->arg_type[i]) {
1547 case STRING_RESULT:
1548 if (n == 2 && args->args[i]) {
1549 if ((signed)i != j) {
1550 m = MY_MIN(args->lengths[i], sizeof(fn) - 1);
1551 memcpy(fn, args->args[i], m);
1552 fn[m] = 0;
1553 j = -1;
1554 fl = GetFileLength(fn);
1555 } // endif i
1556
1557 memlen += fl * M;
1558 } else if (n == 1) {
1559 if (i == 0)
1560 memlen += sizeof(BSON); // For Jbin functions
1561
1562 memlen += args->lengths[i] * M; // Estimate parse memory
1563 } else if (n == 3)
1564 memlen += sizeof(JVALUE);
1565
1566 memlen += sizeof(TYPVAL<PSZ>);
1567 break;
1568 case INT_RESULT:
1569 memlen += sizeof(TYPVAL<int>);
1570 break;
1571 case REAL_RESULT:
1572 case DECIMAL_RESULT:
1573 memlen += sizeof(TYPVAL<double>);
1574 break;
1575 case TIME_RESULT:
1576 case ROW_RESULT:
1577 default:
1578 // What should we do here ?
1579 break;
1580 } // endswitch arg_type
1581
1582 } // endfor i
1583
1584 return false;
1585} // end of CalcLen
1586
1587/*********************************************************************************/
1588/* Check if the calculated memory is enough. */
1589/*********************************************************************************/
1590static my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n,
1591 my_bool m, my_bool obj = false, my_bool mod = false)
1592{
1593 unsigned long rl, ml;
1594 my_bool b = false;
1595
1596 n = MY_MIN(n, args->arg_count);
1597
1598 for (uint i = 0; i < n; i++)
1599 if (IsJson(args, i) == 2 ||
1600 (b = (m && !i && args->arg_type[0] == STRING_RESULT && !IsJson(args, 0)))) {
1601 if (CalcLen(args, obj, rl, ml, mod))
1602 return true;
1603 else if (b) {
1604 ulong len;
1605 char *p = args->args[0];
1606
1607 // Is this a file name?
1608 if (p && !strchr("[{ \t\r\n", *p) && (len = GetFileLength(p)))
1609 ml += len * (M + 1);
1610 else
1611 ml += args->lengths[0] * M;
1612
1613 } // endif b
1614
1615 ml += g->More;
1616
1617 if (ml > g->Sarea_Size) {
1618 FreeSarea(g);
1619
1620 if (AllocSarea(g, ml)) {
1621 char errmsg[MAX_STR];
1622
1623 snprintf(errmsg, sizeof(errmsg) - 1, MSG(WORK_AREA), g->Message);
1624 strcpy(g->Message, errmsg);
1625 return true;
1626 } // endif SareaAlloc
1627
1628 g->Createas = 0;
1629 g->Xchk = NULL;
1630 initid->max_length = rl;
1631 } // endif Size
1632
1633 break;
1634 } // endif IsJson
1635
1636 JsonSubSet(g);
1637 return false;
1638} // end of CheckMemory
1639
1640/*********************************************************************************/
1641/* Make a zero terminated string from the passed argument. */
1642/*********************************************************************************/
1643static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i)
1644{
1645 if (args->arg_count > (unsigned)i && args->args[i]) {
1646 int n = args->lengths[i];
1647 PSZ s = (PSZ)PlgDBSubAlloc(g, NULL, n + 1);
1648
1649 if (s) {
1650 memcpy(s, args->args[i], n);
1651 s[n] = 0;
1652 } else
1653 PUSH_WARNING(g->Message);
1654
1655 return s;
1656 } else
1657 return NULL;
1658
1659} // end of MakePSZ
1660
1661/*********************************************************************************/
1662/* Make a valid key from the passed argument. */
1663/*********************************************************************************/
1664static PCSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
1665{
1666 if (args->arg_count > (unsigned)i) {
1667 int j = 0, n = args->attribute_lengths[i];
1668 my_bool b; // true if attribute is zero terminated
1669 PSZ p;
1670 const char *s = args->attributes[i];
1671
1672 if (s && *s && (n || *s == '\'')) {
1673 if ((b = (!n || !s[n])))
1674 n = strlen(s);
1675
1676 if (IsJson(args, i))
1677 j = (int)(strchr(s, '_') - s + 1);
1678
1679 if (j && n > j) {
1680 s += j;
1681 n -= j;
1682 } else if (*s == '\'' && s[n-1] == '\'') {
1683 s++;
1684 n -= 2;
1685 b = false;
1686 } // endif *s
1687
1688 if (n < 1)
1689 return (char*) "Key";
1690
1691 if (!b) {
1692 if ((p = (PSZ)PlgDBSubAlloc(g, NULL, n + 1))) {
1693 memcpy(p, s, n);
1694 p[n] = 0;
1695 } else
1696 PUSH_WARNING(g->Message);
1697
1698 s = p;
1699 } // endif b
1700
1701 } // endif s
1702
1703 return (char*) s;
1704 } // endif count
1705
1706 return (char*) "Key";
1707} // end of MakeKey
1708
1709/*********************************************************************************/
1710/* Parse a json file. */
1711/*********************************************************************************/
1712static PJSON ParseJsonFile(PGLOBAL g, char *fn, int *pretty, int& len)
1713{
1714 char *memory;
1715 HANDLE hFile;
1716 MEMMAP mm;
1717 PJSON jsp;
1718
1719 /*******************************************************************************/
1720 /* Create the mapping file object. */
1721 /*******************************************************************************/
1722 hFile = CreateFileMap(g, fn, &mm, MODE_READ, false);
1723
1724 if (hFile == INVALID_HANDLE_VALUE) {
1725 DWORD rc = GetLastError();
1726
1727 if (!(*g->Message))
1728 sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
1729
1730 return NULL;
1731 } // endif hFile
1732
1733 /*******************************************************************************/
1734 /* Get the file size (assuming file is smaller than 4 GB) */
1735 /*******************************************************************************/
1736 len = mm.lenL;
1737 memory = (char *)mm.memory;
1738
1739 if (!len) { // Empty or deleted file
1740 CloseFileHandle(hFile);
1741 return NULL;
1742 } // endif len
1743
1744 if (!memory) {
1745 CloseFileHandle(hFile);
1746 sprintf(g->Message, MSG(MAP_VIEW_ERROR), fn, GetLastError());
1747 return NULL;
1748 } // endif Memory
1749
1750 CloseFileHandle(hFile); // Not used anymore
1751
1752 /*********************************************************************************/
1753 /* Parse the json file and allocate its tree structure. */
1754 /*********************************************************************************/
1755 g->Message[0] = 0;
1756 jsp = ParseJson(g, memory, len, pretty);
1757 CloseMemMap(memory, len);
1758 return jsp;
1759} // end of ParseJsonFile
1760
1761/*********************************************************************************/
1762/* Return a json file contains. */
1763/*********************************************************************************/
1764static char *GetJsonFile(PGLOBAL g, char *fn)
1765{
1766 char *str;
1767 int h, n, len;
1768
1769#if defined(UNIX) || defined(UNIV_LINUX)
1770 h= open(fn, O_RDONLY);
1771#else
1772 h= open(fn, _O_RDONLY, _O_TEXT);
1773#endif
1774
1775 if (h == -1) {
1776 sprintf(g->Message, "Error %d opening %s", errno, fn);
1777 return NULL;
1778 } // endif h
1779
1780 if ((len = _filelength(h)) < 0) {
1781 sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", fn);
1782 close(h);
1783 return NULL;
1784 } // endif len
1785
1786 if ((str = (char*)PlgDBSubAlloc(g, NULL, len + 1))) {
1787 if ((n = read(h, str, len)) < 0) {
1788 sprintf(g->Message, "Error %d reading %d bytes from %s", errno, len, fn);
1789 return NULL;
1790 } // endif n
1791
1792 str[n] = 0;
1793 close(h);
1794 } // endif str
1795
1796 return str;
1797} // end of GetJsonFile
1798
1799/*********************************************************************************/
1800/* Make a JSON value from the passed argument. */
1801/*********************************************************************************/
1802static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, uint i, PJSON *top = NULL)
1803{
1804 char *sap = (args->arg_count > i) ? args->args[i] : NULL;
1805 int n, len;
1806 short c;
1807 long long bigint;
1808 PJSON jsp;
1809 PJVAL jvp = new(g) JVALUE;
1810
1811 if (top)
1812 *top = NULL;
1813
1814 if (sap) switch (args->arg_type[i]) {
1815 case STRING_RESULT:
1816 if ((len = args->lengths[i])) {
1817 if ((n = IsJson(args, i)) < 3)
1818 sap = MakePSZ(g, args, i);
1819
1820 if (n) {
1821 if (n == 3) {
1822 if (top)
1823 *top = ((PBSON)sap)->Top;
1824
1825 jsp = ((PBSON)sap)->Jsp;
1826 } else {
1827 if (n == 2) {
1828 if (!(sap = GetJsonFile(g, sap))) {
1829 PUSH_WARNING(g->Message);
1830 return jvp;
1831 } // endif sap
1832
1833 len = strlen(sap);
1834 } // endif n
1835
1836 if (!(jsp = ParseJson(g, sap, strlen(sap))))
1837 PUSH_WARNING(g->Message);
1838 else if (top)
1839 *top = jsp;
1840
1841 } // endif's n
1842
1843 if (jsp && jsp->GetType() == TYPE_JVAL)
1844 jvp = (PJVAL)jsp;
1845 else
1846 jvp->SetValue(jsp);
1847
1848 } else {
1849 c = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
1850 jvp->SetString(g, sap, c);
1851 } // endif n
1852
1853 } // endif len
1854
1855 break;
1856 case INT_RESULT:
1857 bigint = *(long long*)sap;
1858
1859 if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
1860 (bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
1861 jvp->SetTiny(g, (char)bigint);
1862 else
1863 jvp->SetBigint(g, bigint);
1864
1865 break;
1866 case REAL_RESULT:
1867 jvp->SetFloat(g, *(double*)sap);
1868 break;
1869 case DECIMAL_RESULT:
1870 jvp->SetFloat(g, atof(MakePSZ(g, args, i)));
1871 break;
1872 case TIME_RESULT:
1873 case ROW_RESULT:
1874 default:
1875 break;
1876 } // endswitch arg_type
1877
1878 return jvp;
1879} // end of MakeValue
1880
1881/*********************************************************************************/
1882/* Try making a JSON value of the passed type from the passed argument. */
1883/*********************************************************************************/
1884static PJVAL MakeTypedValue(PGLOBAL g, UDF_ARGS *args, uint i,
1885 JTYP type, PJSON *top = NULL)
1886{
1887 char *sap;
1888 PJSON jsp;
1889 PJVAL jvp = MakeValue(g, args, i, top);
1890
1891 //if (type == TYPE_JSON) {
1892 // if (jvp->GetValType() >= TYPE_JSON)
1893 // return jvp;
1894
1895 //} else if (jvp->GetValType() == type)
1896 // return jvp;
1897
1898 if (jvp->GetValType() == TYPE_STRG) {
1899 sap = jvp->GetString(g);
1900
1901 if ((jsp = ParseJson(g, sap, strlen(sap)))) {
1902 if ((type == TYPE_JSON && jsp->GetType() != TYPE_JVAL) || jsp->GetType() == type) {
1903 if (top)
1904 *top = jsp;
1905
1906 jvp->SetValue(jsp);
1907 } // endif Type
1908
1909 } // endif jsp
1910
1911 } // endif Type
1912
1913 return jvp;
1914} // end of MakeTypedValue
1915
1916/*********************************************************************************/
1917/* Make a Json value containing the parameter. */
1918/*********************************************************************************/
1919my_bool jsonvalue_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
1920{
1921 unsigned long reslen, memlen;
1922
1923 if (args->arg_count > 1) {
1924 strcpy(message, "Cannot accept more than 1 argument");
1925 return true;
1926 } else
1927 CalcLen(args, false, reslen, memlen);
1928
1929 return JsonInit(initid, args, message, false, reslen, memlen);
1930} // end of jsonvalue_init
1931
1932char *jsonvalue(UDF_INIT *initid, UDF_ARGS *args, char *result,
1933 unsigned long *res_length, char *, char *)
1934{
1935 char *str;
1936 PGLOBAL g = (PGLOBAL)initid->ptr;
1937
1938 if (!g->Xchk) {
1939 if (!CheckMemory(g, initid, args, 1, false)) {
1940 PJVAL jvp = MakeValue(g, args, 0);
1941
1942 if (!(str = Serialize(g, jvp, NULL, 0)))
1943 str = strcpy(result, g->Message);
1944
1945 } else
1946 str = strcpy(result, g->Message);
1947
1948 // Keep result of constant function
1949 g->Xchk = (initid->const_item) ? str : NULL;
1950 } else
1951 str = (char*)g->Xchk;
1952
1953 *res_length = strlen(str);
1954 return str;
1955} // end of JsonValue
1956
1957void jsonvalue_deinit(UDF_INIT* initid)
1958{
1959 JsonFreeMem((PGLOBAL)initid->ptr);
1960} // end of jsonvalue_deinit
1961
1962/*********************************************************************************/
1963/* Make a Json array containing all the parameters. */
1964/*********************************************************************************/
1965my_bool json_make_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
1966{
1967 unsigned long reslen, memlen;
1968
1969 CalcLen(args, false, reslen, memlen);
1970 return JsonInit(initid, args, message, false, reslen, memlen);
1971} // end of json_make_array_init
1972
1973char *json_make_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
1974 unsigned long *res_length, char *, char *)
1975{
1976 char *str;
1977 PGLOBAL g = (PGLOBAL)initid->ptr;
1978
1979 if (!g->Xchk) {
1980 if (!CheckMemory(g, initid, args, args->arg_count, false)) {
1981 PJAR arp = new(g)JARRAY;
1982
1983 for (uint i = 0; i < args->arg_count; i++)
1984 arp->AddValue(g, MakeValue(g, args, i));
1985
1986 arp->InitArray(g);
1987
1988 if (!(str = Serialize(g, arp, NULL, 0)))
1989 str = strcpy(result, g->Message);
1990
1991 } else
1992 str = strcpy(result, g->Message);
1993
1994 // Keep result of constant function
1995 g->Xchk = (initid->const_item) ? str : NULL;
1996 } else
1997 str = (char*)g->Xchk;
1998
1999 *res_length = strlen(str);
2000 return str;
2001} // end of json_make_array
2002
2003void json_make_array_deinit(UDF_INIT* initid)
2004{
2005 JsonFreeMem((PGLOBAL)initid->ptr);
2006} // end of json_make_array_deinit
2007
2008/*********************************************************************************/
2009/* Add one or several values to a Json array. */
2010/*********************************************************************************/
2011my_bool json_array_add_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2012{
2013 unsigned long reslen, memlen;
2014
2015 if (args->arg_count < 2) {
2016 strcpy(message, "This function must have at least 2 arguments");
2017 return true;
2018 //} else if (!IsJson(args, 0, true)) {
2019 // strcpy(message, "First argument must be a valid json string or item");
2020 // return true;
2021 } else
2022 CalcLen(args, false, reslen, memlen);
2023
2024 if (!JsonInit(initid, args, message, true, reslen, memlen)) {
2025 PGLOBAL g = (PGLOBAL)initid->ptr;
2026
2027 // This is a constant function
2028 g->N = (initid->const_item) ? 1 : 0;
2029
2030 // This is to avoid double execution when using prepared statements
2031 if (IsJson(args, 0) > 1)
2032 initid->const_item = 0;
2033
2034 return false;
2035 } else
2036 return true;
2037
2038} // end of json_array_add_values_init
2039
2040char *json_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
2041 unsigned long *res_length, char *is_null, char *)
2042{
2043 char *str = NULL;
2044 PGLOBAL g = (PGLOBAL)initid->ptr;
2045
2046 if (!g->Xchk) {
2047 if (!CheckMemory(g, initid, args, args->arg_count, true)) {
2048 PJSON top;
2049 PJAR arp;
2050 PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top);
2051
2052 if (jvp->GetValType() != TYPE_JAR) {
2053 arp = new(g)JARRAY;
2054 arp->AddValue(g, jvp);
2055 top = arp;
2056 } else
2057 arp = jvp->GetArray();
2058
2059 for (uint i = 1; i < args->arg_count; i++)
2060 arp->AddValue(g, MakeValue(g, args, i));
2061
2062 arp->InitArray(g);
2063 str = MakeResult(g, args, top, args->arg_count);
2064 } // endif CheckMemory
2065
2066 if (!str) {
2067 PUSH_WARNING(g->Message);
2068 str = args->args[0];
2069 } // endif str
2070
2071 // Keep result of constant function
2072 g->Xchk = (g->N) ? str : NULL;
2073 } else
2074 str = (char*)g->Xchk;
2075
2076 if (!str) {
2077 *res_length = 0;
2078 *is_null = 1;
2079 } else
2080 *res_length = strlen(str);
2081
2082 return str;
2083} // end of json_array_add_values
2084
2085void json_array_add_values_deinit(UDF_INIT* initid)
2086{
2087 JsonFreeMem((PGLOBAL)initid->ptr);
2088} // end of json_array_add_values_deinit
2089
2090/*********************************************************************************/
2091/* Add one value to a Json array. */
2092/*********************************************************************************/
2093my_bool json_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2094{
2095 unsigned long reslen, memlen;
2096
2097 if (args->arg_count < 2) {
2098 strcpy(message, "This function must have at least 2 arguments");
2099 return true;
2100 //} else if (!IsJson(args, 0, true)) {
2101 // strcpy(message, "First argument is not a valid Json item");
2102 // return true;
2103 } else
2104 CalcLen(args, false, reslen, memlen, true);
2105
2106 if (!JsonInit(initid, args, message, true, reslen, memlen)) {
2107 PGLOBAL g = (PGLOBAL)initid->ptr;
2108
2109 // This is a constant function
2110 g->N = (initid->const_item) ? 1 : 0;
2111
2112 // This is to avoid double execution when using prepared statements
2113 if (IsJson(args, 0) > 1)
2114 initid->const_item = 0;
2115
2116 return false;
2117 } else
2118 return true;
2119
2120} // end of json_array_add_init
2121
2122char *json_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
2123 unsigned long *res_length, char *is_null, char *error)
2124{
2125 char *str = NULL;
2126 PGLOBAL g = (PGLOBAL)initid->ptr;
2127
2128 if (g->Xchk) {
2129 // This constant function was recalled
2130 str = (char*)g->Xchk;
2131 goto fin;
2132 } // endif Xchk
2133
2134 if (!CheckMemory(g, initid, args, 2, false, false, true)) {
2135 int *x;
2136 uint n = 2;
2137 PJSON jsp, top;
2138 PJVAL jvp;
2139 PJAR arp;
2140
2141 jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
2142 jsp = jvp->GetJson();
2143 x = GetIntArgPtr(g, args, n);
2144
2145 if (CheckPath(g, args, jsp, jvp, 2))
2146 PUSH_WARNING(g->Message);
2147 else if (jvp) {
2148 PGLOBAL gb = GetMemPtr(g, args, 0);
2149
2150 if (jvp->GetValType() != TYPE_JAR) {
2151 if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
2152 arp->AddValue(gb, JvalNew(gb, TYPE_JVAL, jvp));
2153 jvp->SetValue(arp);
2154
2155 if (!top)
2156 top = arp;
2157
2158 } // endif arp
2159
2160 } else
2161 arp = jvp->GetArray();
2162
2163 if (arp) {
2164 arp->AddValue(gb, MakeValue(gb, args, 1), x);
2165 arp->InitArray(gb);
2166 str = MakeResult(g, args, top, n);
2167 } else
2168 PUSH_WARNING(gb->Message);
2169
2170 } else {
2171 PUSH_WARNING("Target is not an array");
2172 // if (g->Mrr) *error = 1; (only if no path)
2173 } // endif jvp
2174
2175 } // endif CheckMemory
2176
2177 // In case of error or file, return unchanged argument
2178 if (!str)
2179 str = MakePSZ(g, args, 0);
2180
2181 if (g->N)
2182 // Keep result of constant function
2183 g->Xchk = str;
2184
2185 fin:
2186 if (!str) {
2187 *res_length = 0;
2188 *is_null = 1;
2189 *error = 1;
2190 } else
2191 *res_length = strlen(str);
2192
2193 return str;
2194} // end of json_array_add
2195
2196void json_array_add_deinit(UDF_INIT* initid)
2197{
2198 JsonFreeMem((PGLOBAL)initid->ptr);
2199} // end of json_array_add_deinit
2200
2201/*********************************************************************************/
2202/* Delete a value from a Json array. */
2203/*********************************************************************************/
2204my_bool json_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2205{
2206 unsigned long reslen, memlen;
2207
2208 if (args->arg_count < 2) {
2209 strcpy(message, "This function must have at least 2 arguments");
2210 return true;
2211 } else
2212 CalcLen(args, false, reslen, memlen, true);
2213
2214 if (!JsonInit(initid, args, message, true, reslen, memlen)) {
2215 PGLOBAL g = (PGLOBAL)initid->ptr;
2216
2217 // This is a constant function
2218 g->N = (initid->const_item) ? 1 : 0;
2219
2220 // This is to avoid double execution when using prepared statements
2221 if (IsJson(args, 0) > 1)
2222 initid->const_item = 0;
2223
2224 return false;
2225 } else
2226 return true;
2227
2228} // end of json_array_delete_init
2229
2230char *json_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
2231 unsigned long *res_length, char *is_null, char *error)
2232{
2233 char *str = NULL;
2234 PGLOBAL g = (PGLOBAL)initid->ptr;
2235
2236 if (g->Xchk) {
2237 // This constant function was recalled
2238 str = (char*)g->Xchk;
2239 goto fin;
2240 } // endif Xchk
2241
2242 if (!CheckMemory(g, initid, args, 1, false, false, true)) {
2243 int *x;
2244 uint n = 1;
2245 PJSON top;
2246 PJAR arp;
2247 PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
2248
2249 if (!(x = GetIntArgPtr(g, args, n)))
2250 PUSH_WARNING("Missing or null array index");
2251 else if (CheckPath(g, args, jvp->GetJson(), jvp, 1))
2252 PUSH_WARNING(g->Message);
2253 else if (jvp && jvp->GetValType() == TYPE_JAR) {
2254 arp = jvp->GetArray();
2255 arp->DeleteValue(*x);
2256 arp->InitArray(GetMemPtr(g, args, 0));
2257 str = MakeResult(g, args, top, n);
2258 } else {
2259 PUSH_WARNING("First argument target is not an array");
2260// if (g->Mrr) *error = 1;
2261 } // endif jvp
2262
2263 } // endif CheckMemory
2264
2265 // In case of error or file, return unchanged argument
2266 if (!str)
2267 str = MakePSZ(g, args, 0);
2268
2269 if (g->N)
2270 // Keep result of constant function
2271 g->Xchk = str;
2272
2273 fin:
2274 if (!str) {
2275 *is_null = 1;
2276 *error = 1;
2277 *res_length = 0;
2278 } else
2279 *res_length = strlen(str);
2280
2281 return str;
2282} // end of json_array_delete
2283
2284void json_array_delete_deinit(UDF_INIT* initid)
2285{
2286 JsonFreeMem((PGLOBAL)initid->ptr);
2287} // end of json_array_delete_deinit
2288
2289/*********************************************************************************/
2290/* Sum big integer values from a Json array. */
2291/*********************************************************************************/
2292my_bool jsonsum_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2293{
2294 unsigned long reslen, memlen, more;
2295
2296 if (args->arg_count != 1) {
2297 strcpy(message, "This function must have 1 argument");
2298 return true;
2299 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
2300 strcpy(message, "First argument must be a json item");
2301 return true;
2302 } else
2303 CalcLen(args, false, reslen, memlen);
2304
2305 // TODO: calculate this
2306 more = (IsJson(args, 0) != 3) ? 1000 : 0;
2307
2308 return JsonInit(initid, args, message, true, reslen, memlen, more);
2309} // end of jsonsum_int_init
2310
2311long long jsonsum_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
2312{
2313 long long n = 0LL;
2314 PGLOBAL g = (PGLOBAL)initid->ptr;
2315
2316 if (g->N) {
2317 if (!g->Activityp) {
2318 *is_null = 1;
2319 return 0LL;
2320 } else
2321 return *(long long*)g->Activityp;
2322
2323 } else if (initid->const_item)
2324 g->N = 1;
2325
2326 if (!CheckMemory(g, initid, args, 1, false, false, true)) {
2327 PJVAL jvp = MakeValue(g, args, 0);
2328
2329 if (jvp && jvp->GetValType() == TYPE_JAR) {
2330 PJAR arp = jvp->GetArray();
2331
2332 for (int i = 0; i < arp->size(); i++)
2333 n += arp->GetValue(i)->GetBigint();
2334
2335 } else {
2336 PUSH_WARNING("First argument target is not an array");
2337 } // endif jvp
2338
2339 } else {
2340 *error = 1;
2341 n = -1LL;
2342 } // end of CheckMemory
2343
2344 if (g->N) {
2345 // Keep result of constant function
2346 long long *np;
2347
2348 if ((np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long)))) {
2349 *np = n;
2350 g->Activityp = (PACTIVITY)np;
2351 } else
2352 PUSH_WARNING(g->Message);
2353
2354 } // endif const_item
2355
2356 return n;
2357} // end of jsonsum_int
2358
2359void jsonsum_int_deinit(UDF_INIT* initid)
2360{
2361 JsonFreeMem((PGLOBAL)initid->ptr);
2362} // end of jsonsum_int_deinit
2363
2364/*********************************************************************************/
2365/* Sum big integer values from a Json array. */
2366/*********************************************************************************/
2367my_bool jsonsum_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2368{
2369 unsigned long reslen, memlen, more;
2370
2371 if (args->arg_count != 1) {
2372 strcpy(message, "This function must have 1 argument");
2373 return true;
2374 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
2375 strcpy(message, "First argument must be a json item");
2376 return true;
2377 } else
2378 CalcLen(args, false, reslen, memlen);
2379
2380 // TODO: calculate this
2381 more = (IsJson(args, 0) != 3) ? 1000 : 0;
2382
2383 return JsonInit(initid, args, message, true, reslen, memlen, more);
2384} // end of jsonsum_real_init
2385
2386double jsonsum_real(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
2387{
2388 double n = 0.0;
2389 PGLOBAL g = (PGLOBAL)initid->ptr;
2390
2391 if (g->N) {
2392 if (!g->Activityp) {
2393 *is_null = 1;
2394 return 0.0;
2395 } else
2396 return *(double*)g->Activityp;
2397
2398 } else if (initid->const_item)
2399 g->N = 1;
2400
2401 if (!CheckMemory(g, initid, args, 1, false, false, true)) {
2402 PJVAL jvp = MakeValue(g, args, 0);
2403
2404 if (jvp && jvp->GetValType() == TYPE_JAR) {
2405 PJAR arp = jvp->GetArray();
2406
2407 for (int i = 0; i < arp->size(); i++)
2408 n += arp->GetValue(i)->GetFloat();
2409
2410 } else {
2411 PUSH_WARNING("First argument target is not an array");
2412 } // endif jvp
2413
2414 } else {
2415 *error = 1;
2416 n = -1.0;
2417 } // endif CheckMemory
2418
2419 if (g->N) {
2420 // Keep result of constant function
2421 double *np;
2422
2423 if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
2424 *np = n;
2425 g->Activityp = (PACTIVITY)np;
2426 } else {
2427 PUSH_WARNING(g->Message);
2428 *error = 1;
2429 n = -1.0;
2430 } // endif np
2431
2432 } // endif const_item
2433
2434 return n;
2435} // end of jsonsum_real
2436
2437void jsonsum_real_deinit(UDF_INIT* initid)
2438{
2439 JsonFreeMem((PGLOBAL)initid->ptr);
2440} // end of jsonsum_real_deinit
2441
2442/*********************************************************************************/
2443/* Returns the average of big integer values from a Json array. */
2444/*********************************************************************************/
2445my_bool jsonavg_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2446{
2447 return jsonsum_real_init(initid, args, message);
2448} // end of jsonavg_real_init
2449
2450double jsonavg_real(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
2451{
2452 double n = 0.0;
2453 PGLOBAL g = (PGLOBAL)initid->ptr;
2454
2455 if (g->N) {
2456 if (!g->Activityp) {
2457 *is_null = 1;
2458 return 0.0;
2459 } else
2460 return *(double*)g->Activityp;
2461
2462 } else if (initid->const_item)
2463 g->N = 1;
2464
2465 if (!CheckMemory(g, initid, args, 1, false, false, true)) {
2466 PJVAL jvp = MakeValue(g, args, 0);
2467
2468 if (jvp && jvp->GetValType() == TYPE_JAR) {
2469 PJAR arp = jvp->GetArray();
2470
2471 if (arp->size()) {
2472 for (int i = 0; i < arp->size(); i++)
2473 n += arp->GetValue(i)->GetFloat();
2474
2475 n /= arp->size();
2476 } // endif size
2477
2478 } else {
2479 PUSH_WARNING("First argument target is not an array");
2480 } // endif jvp
2481
2482 } else {
2483 *error = 1;
2484 n = -1.0;
2485 } // endif CheckMemory
2486
2487 if (g->N) {
2488 // Keep result of constant function
2489 double *np;
2490
2491 if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
2492 *np = n;
2493 g->Activityp = (PACTIVITY)np;
2494 } else {
2495 *error = 1;
2496 n = -1.0;
2497 } // endif np
2498
2499 } // endif const_item
2500
2501 return n;
2502} // end of jsonavg_real
2503
2504void jsonavg_real_deinit(UDF_INIT* initid)
2505{
2506 JsonFreeMem((PGLOBAL)initid->ptr);
2507} // end of jsonavg_real_deinit
2508
2509/*********************************************************************************/
2510/* Make a Json Object containing all the parameters. */
2511/*********************************************************************************/
2512my_bool json_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2513{
2514 unsigned long reslen, memlen;
2515
2516 CalcLen(args, true, reslen, memlen);
2517 return JsonInit(initid, args, message, false, reslen, memlen);
2518} // end of json_make_object_init
2519
2520char *json_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
2521 unsigned long *res_length, char *, char *)
2522{
2523 char *str = NULL;
2524 PGLOBAL g = (PGLOBAL)initid->ptr;
2525
2526 if (!g->Xchk) {
2527 if (!CheckMemory(g, initid, args, args->arg_count, false, false, true)) {
2528 PJOB objp;
2529
2530 if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
2531 for (uint i = 0; i < args->arg_count; i++)
2532 objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
2533
2534 str = Serialize(g, objp, NULL, 0);
2535 } // endif objp
2536
2537 } // endif CheckMemory
2538
2539 if (!str)
2540 str = strcpy(result, g->Message);
2541
2542 // Keep result of constant function
2543 g->Xchk = (initid->const_item) ? str : NULL;
2544 } else
2545 str = (char*)g->Xchk;
2546
2547 *res_length = strlen(str);
2548 return str;
2549} // end of json_make_object
2550
2551void json_make_object_deinit(UDF_INIT* initid)
2552{
2553 JsonFreeMem((PGLOBAL)initid->ptr);
2554} // end of json_make_object_deinit
2555
2556/*********************************************************************************/
2557/* Make a Json Object containing all not null parameters. */
2558/*********************************************************************************/
2559my_bool json_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args,
2560 char *message)
2561{
2562 unsigned long reslen, memlen;
2563
2564 CalcLen(args, true, reslen, memlen);
2565 return JsonInit(initid, args, message, false, reslen, memlen);
2566} // end of json_object_nonull_init
2567
2568char *json_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
2569 unsigned long *res_length, char *, char *)
2570{
2571 char *str = NULL;
2572 PGLOBAL g = (PGLOBAL)initid->ptr;
2573
2574 if (!g->Xchk) {
2575 if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
2576 PJVAL jvp;
2577 PJOB objp;
2578
2579 if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
2580 for (uint i = 0; i < args->arg_count; i++)
2581 if (!(jvp = MakeValue(g, args, i))->IsNull())
2582 objp->SetValue(g, jvp, MakeKey(g, args, i));
2583
2584 str = Serialize(g, objp, NULL, 0);
2585 } // endif objp
2586
2587 } // endif CheckMemory
2588
2589 if (!str)
2590 str = strcpy(result, g->Message);
2591
2592 // Keep result of constant function
2593 g->Xchk = (initid->const_item) ? str : NULL;
2594 } else
2595 str = (char*)g->Xchk;
2596
2597 *res_length = strlen(str);
2598 return str;
2599} // end of json_object_nonull
2600
2601void json_object_nonull_deinit(UDF_INIT* initid)
2602{
2603 JsonFreeMem((PGLOBAL)initid->ptr);
2604} // end of json_object_nonull_deinit
2605
2606/*********************************************************************************/
2607/* Make a Json Object containing all the key/value parameters. */
2608/*********************************************************************************/
2609my_bool json_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2610{
2611 unsigned long reslen, memlen;
2612
2613 if (args->arg_count % 2) {
2614 strcpy(message, "This function must have an even number of arguments");
2615 return true;
2616 } // endif arg_count
2617
2618 CalcLen(args, true, reslen, memlen);
2619 return JsonInit(initid, args, message, false, reslen, memlen);
2620} // end of json_object_key_init
2621
2622char *json_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
2623 unsigned long *res_length, char *, char *)
2624{
2625 char *str = NULL;
2626 PGLOBAL g = (PGLOBAL)initid->ptr;
2627
2628 if (!g->Xchk) {
2629 if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
2630 PJOB objp;
2631
2632 if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
2633 for (uint i = 0; i < args->arg_count; i += 2)
2634 objp->SetValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i));
2635
2636 str = Serialize(g, objp, NULL, 0);
2637 } // endif objp
2638
2639 } // endif CheckMemory
2640
2641 if (!str)
2642 str = strcpy(result, g->Message);
2643
2644 // Keep result of constant function
2645 g->Xchk = (initid->const_item) ? str : NULL;
2646 } else
2647 str = (char*)g->Xchk;
2648
2649 *res_length = strlen(str);
2650 return str;
2651} // end of json_object_key
2652
2653void json_object_key_deinit(UDF_INIT* initid)
2654{
2655 JsonFreeMem((PGLOBAL)initid->ptr);
2656} // end of json_object_key_deinit
2657
2658/*********************************************************************************/
2659/* Add or replace a value in a Json Object. */
2660/*********************************************************************************/
2661my_bool json_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2662{
2663 unsigned long reslen, memlen;
2664
2665 if (args->arg_count < 2) {
2666 strcpy(message, "This function must have at least 2 arguments");
2667 return true;
2668 } else if (!IsJson(args, 0)) {
2669 strcpy(message, "First argument must be a json item");
2670 return true;
2671 } else
2672 CalcLen(args, true, reslen, memlen, true);
2673
2674 if (!JsonInit(initid, args, message, true, reslen, memlen)) {
2675 PGLOBAL g = (PGLOBAL)initid->ptr;
2676
2677 // This is a constant function
2678 g->N = (initid->const_item) ? 1 : 0;
2679
2680 // This is to avoid double execution when using prepared statements
2681 if (IsJson(args, 0) > 1)
2682 initid->const_item = 0;
2683
2684 return false;
2685 } else
2686 return true;
2687
2688} // end of json_object_add_init
2689
2690char *json_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
2691 unsigned long *res_length, char *is_null, char *error)
2692{
2693 PCSZ key;
2694 char *str = NULL;
2695 PGLOBAL g = (PGLOBAL)initid->ptr;
2696
2697 if (g->Xchk) {
2698 // This constant function was recalled
2699 str = (char*)g->Xchk;
2700 goto fin;
2701 } // endif Xchk
2702
2703 if (!CheckMemory(g, initid, args, 2, false, true, true)) {
2704 PJOB jobp;
2705 PJVAL jvp;
2706 PJSON jsp, top;
2707 PGLOBAL gb = GetMemPtr(g, args, 0);
2708
2709 jvp = MakeValue(g, args, 0, &top);
2710 jsp = jvp->GetJson();
2711
2712 if (CheckPath(g, args, jsp, jvp, 2))
2713 PUSH_WARNING(g->Message);
2714 else if (jvp && jvp->GetValType() == TYPE_JOB) {
2715 jobp = jvp->GetObject();
2716 jvp = MakeValue(gb, args, 1);
2717 key = MakeKey(gb, args, 1);
2718 jobp->SetValue(gb, jvp, key);
2719 str = MakeResult(g, args, top);
2720 } else {
2721 PUSH_WARNING("First argument target is not an object");
2722// if (g->Mrr) *error = 1; (only if no path)
2723 } // endif jvp
2724
2725 } // endif CheckMemory
2726
2727 // In case of error or file, return unchanged argument
2728 if (!str)
2729 str = MakePSZ(g, args, 0);
2730
2731 if (g->N)
2732 // Keep result of constant function
2733 g->Xchk = str;
2734
2735 fin:
2736 if (!str) {
2737 *is_null = 1;
2738 *error = 1;
2739 *res_length = 0;
2740 } else
2741 *res_length = strlen(str);
2742
2743 return str;
2744} // end of json_object_add
2745
2746void json_object_add_deinit(UDF_INIT* initid)
2747{
2748 JsonFreeMem((PGLOBAL)initid->ptr);
2749} // end of json_object_add_deinit
2750
2751/*********************************************************************************/
2752/* Delete a value from a Json object. */
2753/*********************************************************************************/
2754my_bool json_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2755{
2756 unsigned long reslen, memlen;
2757
2758 if (args->arg_count < 2) {
2759 strcpy(message, "This function must have 2 or 3 arguments");
2760 return true;
2761 } else if (!IsJson(args, 0)) {
2762 strcpy(message, "First argument must be a json item");
2763 return true;
2764 } else if (args->arg_type[1] != STRING_RESULT) {
2765 strcpy(message, "Second argument must be a key string");
2766 return true;
2767 } else
2768 CalcLen(args, true, reslen, memlen, true);
2769
2770 if (!JsonInit(initid, args, message, true, reslen, memlen)) {
2771 PGLOBAL g = (PGLOBAL)initid->ptr;
2772
2773 // This is a constant function
2774 g->N = (initid->const_item) ? 1 : 0;
2775
2776 // This is to avoid double execution when using prepared statements
2777 if (IsJson(args, 0) > 1)
2778 initid->const_item = 0;
2779
2780 return false;
2781 } else
2782 return true;
2783
2784} // end of json_object_delete_init
2785
2786char *json_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
2787 unsigned long *res_length, char *is_null, char *error)
2788{
2789 char *str = NULL;
2790 PGLOBAL g = (PGLOBAL)initid->ptr;
2791
2792 if (g->Xchk) {
2793 // This constant function was recalled
2794 str = (char*)g->Xchk;
2795 goto fin;
2796 } // endif Xchk
2797
2798 if (!CheckMemory(g, initid, args, 1, false, true, true)) {
2799 PCSZ key;
2800 PJOB jobp;
2801 PJSON jsp, top;
2802 PJVAL jvp = MakeValue(g, args, 0, &top);
2803
2804 jsp = jvp->GetJson();
2805
2806 if (CheckPath(g, args, jsp, jvp, 2))
2807 PUSH_WARNING(g->Message);
2808 else if (jvp && jvp->GetValType() == TYPE_JOB) {
2809 key = MakeKey(GetMemPtr(g, args, 0), args, 1);
2810 jobp = jvp->GetObject();
2811 jobp->DeleteKey(key);
2812 str = MakeResult(g, args, top);
2813 } else {
2814 PUSH_WARNING("First argument target is not an object");
2815// if (g->Mrr) *error = 1; (only if no path)
2816 } // endif jvp
2817
2818 } // endif CheckMemory
2819
2820 // In case of error or file, return unchanged argument
2821 if (!str)
2822 str = MakePSZ(g, args, 0);
2823
2824 if (g->N)
2825 // Keep result of constant function
2826 g->Xchk = str;
2827
2828 fin:
2829 if (!str) {
2830 *is_null = 1;
2831 *error = 1;
2832 *res_length = 0;
2833 } else
2834 *res_length = strlen(str);
2835
2836 return str;
2837} // end of json_object_delete
2838
2839void json_object_delete_deinit(UDF_INIT* initid)
2840{
2841 JsonFreeMem((PGLOBAL)initid->ptr);
2842} // end of json_object_delete_deinit
2843
2844/*********************************************************************************/
2845/* Returns an array of the Json object keys. */
2846/*********************************************************************************/
2847my_bool json_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2848{
2849 unsigned long reslen, memlen;
2850
2851 if (args->arg_count != 1) {
2852 strcpy(message, "This function must have 1 argument");
2853 return true;
2854 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
2855 strcpy(message, "Argument must be a json item");
2856 return true;
2857 } else
2858 CalcLen(args, false, reslen, memlen);
2859
2860 return JsonInit(initid, args, message, true, reslen, memlen);
2861} // end of json_object_list_init
2862
2863char *json_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
2864 unsigned long *res_length, char *is_null, char *error)
2865{
2866 char *str = NULL;
2867 PGLOBAL g = (PGLOBAL)initid->ptr;
2868
2869 if (!g->N) {
2870 if (!CheckMemory(g, initid, args, 1, true, true)) {
2871 char *p;
2872 PJSON jsp;
2873 PJVAL jvp = MakeValue(g, args, 0);
2874
2875 if ((p = jvp->GetString(g))) {
2876 if (!(jsp = ParseJson(g, p, strlen(p)))) {
2877 PUSH_WARNING(g->Message);
2878 return NULL;
2879 } // endif jsp
2880
2881 } else
2882 jsp = jvp->GetJson();
2883
2884 if (jsp->GetType() == TYPE_JOB) {
2885 PJAR jarp = ((PJOB)jsp)->GetKeyList(g);
2886
2887 if (!(str = Serialize(g, jarp, NULL, 0)))
2888 PUSH_WARNING(g->Message);
2889
2890 } else {
2891 PUSH_WARNING("First argument is not an object");
2892 if (g->Mrr) *error = 1;
2893 } // endif jvp
2894
2895 } // endif CheckMemory
2896
2897 if (initid->const_item) {
2898 // Keep result of constant function
2899 g->Xchk = str;
2900 g->N = 1; // str can be NULL
2901 } // endif const_item
2902
2903 } else
2904 str = (char*)g->Xchk;
2905
2906 if (!str) {
2907 *is_null = 1;
2908 *res_length = 0;
2909 } else
2910 *res_length = strlen(str);
2911
2912 return str;
2913} // end of json_object_list
2914
2915void json_object_list_deinit(UDF_INIT* initid)
2916{
2917 JsonFreeMem((PGLOBAL)initid->ptr);
2918} // end of json_object_list_deinit
2919
2920/*********************************************************************************/
2921/* Returns an array of the Json object values. */
2922/*********************************************************************************/
2923my_bool json_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
2924{
2925 unsigned long reslen, memlen;
2926
2927 if (args->arg_count != 1) {
2928 strcpy(message, "This function must have 1 argument");
2929 return true;
2930 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
2931 strcpy(message, "Argument must be a json object");
2932 return true;
2933 } else
2934 CalcLen(args, false, reslen, memlen);
2935
2936 return JsonInit(initid, args, message, true, reslen, memlen);
2937} // end of json_object_list_init
2938
2939char *json_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
2940 unsigned long *res_length, char *is_null, char *error)
2941{
2942 char *str = NULL;
2943 PGLOBAL g = (PGLOBAL)initid->ptr;
2944
2945 if (!g->N) {
2946 if (!CheckMemory(g, initid, args, 1, true, true)) {
2947 char *p;
2948 PJSON jsp;
2949 PJVAL jvp = MakeValue(g, args, 0);
2950
2951 if ((p = jvp->GetString(g))) {
2952 if (!(jsp = ParseJson(g, p, strlen(p)))) {
2953 PUSH_WARNING(g->Message);
2954 return NULL;
2955 } // endif jsp
2956
2957 } else
2958 jsp = jvp->GetJson();
2959
2960 if (jsp->GetType() == TYPE_JOB) {
2961 PJAR jarp = ((PJOB)jsp)->GetValList(g);
2962
2963 if (!(str = Serialize(g, jarp, NULL, 0)))
2964 PUSH_WARNING(g->Message);
2965
2966 } else {
2967 PUSH_WARNING("First argument is not an object");
2968 if (g->Mrr) *error = 1;
2969 } // endif jvp
2970
2971 } // endif CheckMemory
2972
2973 if (initid->const_item) {
2974 // Keep result of constant function
2975 g->Xchk = str;
2976 g->N = 1; // str can be NULL
2977 } // endif const_item
2978
2979 } else
2980 str = (char*)g->Xchk;
2981
2982 if (!str) {
2983 *is_null = 1;
2984 *res_length = 0;
2985 } else
2986 *res_length = strlen(str);
2987
2988 return str;
2989} // end of json_object_values
2990
2991void json_object_values_deinit(UDF_INIT* initid)
2992{
2993 JsonFreeMem((PGLOBAL)initid->ptr);
2994} // end of json_object_values_deinit
2995
2996/*********************************************************************************/
2997/* Set the value of JsonGrpSize. */
2998/*********************************************************************************/
2999my_bool jsonset_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3000{
3001 if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
3002 strcpy(message, "This function must have 1 integer argument");
3003 return true;
3004 } else
3005 return false;
3006
3007} // end of jsonset_grp_size_init
3008
3009long long jsonset_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
3010{
3011 long long n = *(long long*)args->args[0];
3012
3013 JsonGrpSize = (uint)n;
3014 return (long long)GetJsonGroupSize();
3015} // end of jsonset_grp_size
3016
3017/*********************************************************************************/
3018/* Get the value of JsonGrpSize. */
3019/*********************************************************************************/
3020my_bool jsonget_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3021{
3022 if (args->arg_count != 0) {
3023 strcpy(message, "This function must have no arguments");
3024 return true;
3025 } else
3026 return false;
3027
3028} // end of jsonget_grp_size_init
3029
3030long long jsonget_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
3031{
3032 return (long long)GetJsonGroupSize();
3033} // end of jsonget_grp_size
3034
3035/*********************************************************************************/
3036/* Make a Json array from values coming from rows. */
3037/*********************************************************************************/
3038my_bool json_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3039{
3040 unsigned long reslen, memlen, n = GetJsonGroupSize();
3041
3042 if (args->arg_count != 1) {
3043 strcpy(message, "This function can only accept 1 argument");
3044 return true;
3045 } else if (IsJson(args, 0) == 3) {
3046 strcpy(message, "This function does not support Jbin arguments");
3047 return true;
3048 } else
3049 CalcLen(args, false, reslen, memlen);
3050
3051 reslen *= n;
3052 memlen += ((memlen - MEMFIX) * (n - 1));
3053
3054 if (JsonInit(initid, args, message, false, reslen, memlen))
3055 return true;
3056
3057 PGLOBAL g = (PGLOBAL)initid->ptr;
3058
3059 PlugSubSet(g, g->Sarea, g->Sarea_Size);
3060 g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR);
3061 g->N = (int)n;
3062 return false;
3063} // end of json_array_grp_init
3064
3065void json_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
3066{
3067 PGLOBAL g = (PGLOBAL)initid->ptr;
3068 PJAR arp = (PJAR)g->Activityp;
3069
3070 if (arp && g->N-- > 0)
3071 arp->AddValue(g, MakeValue(g, args, 0));
3072
3073} // end of json_array_grp_add
3074
3075char *json_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
3076 unsigned long *res_length, char *, char *)
3077{
3078 char *str;
3079 PGLOBAL g = (PGLOBAL)initid->ptr;
3080 PJAR arp = (PJAR)g->Activityp;
3081
3082 if (g->N < 0)
3083 PUSH_WARNING("Result truncated to json_grp_size values");
3084
3085 if (arp) {
3086 arp->InitArray(g);
3087 str = Serialize(g, arp, NULL, 0);
3088 } else
3089 str = NULL;
3090
3091 if (!str)
3092 str = strcpy(result, g->Message);
3093
3094 *res_length = strlen(str);
3095 return str;
3096} // end of json_array_grp
3097
3098void json_array_grp_clear(UDF_INIT *initid, char*, char*)
3099{
3100 PGLOBAL g = (PGLOBAL)initid->ptr;
3101
3102 PlugSubSet(g, g->Sarea, g->Sarea_Size);
3103 g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR);
3104 g->N = GetJsonGroupSize();
3105} // end of json_array_grp_clear
3106
3107void json_array_grp_deinit(UDF_INIT* initid)
3108{
3109 JsonFreeMem((PGLOBAL)initid->ptr);
3110} // end of json_array_grp_deinit
3111
3112/*********************************************************************************/
3113/* Make a Json object from values coming from rows. */
3114/*********************************************************************************/
3115my_bool json_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3116{
3117 unsigned long reslen, memlen, n = GetJsonGroupSize();
3118
3119 if (args->arg_count != 2) {
3120 strcpy(message, "This function requires 2 arguments (key, value)");
3121 return true;
3122 } else if (IsJson(args, 0) == 3) {
3123 strcpy(message, "This function does not support Jbin arguments");
3124 return true;
3125 } else
3126 CalcLen(args, true, reslen, memlen);
3127
3128 reslen *= n;
3129 memlen += ((memlen - MEMFIX) * (n - 1));
3130
3131 if (JsonInit(initid, args, message, false, reslen, memlen))
3132 return true;
3133
3134 PGLOBAL g = (PGLOBAL)initid->ptr;
3135
3136 PlugSubSet(g, g->Sarea, g->Sarea_Size);
3137 g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB);
3138 g->N = (int)n;
3139 return false;
3140} // end of json_object_grp_init
3141
3142void json_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
3143{
3144 PGLOBAL g = (PGLOBAL)initid->ptr;
3145 PJOB objp = (PJOB)g->Activityp;
3146
3147 if (g->N-- > 0)
3148 objp->SetValue(g, MakeValue(g, args, 1), MakePSZ(g, args, 0));
3149
3150} // end of json_object_grp_add
3151
3152char *json_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
3153 unsigned long *res_length, char *, char *)
3154{
3155 char *str;
3156 PGLOBAL g = (PGLOBAL)initid->ptr;
3157 PJOB objp = (PJOB)g->Activityp;
3158
3159 if (g->N < 0)
3160 PUSH_WARNING("Result truncated to json_grp_size values");
3161
3162 if (!objp || !(str = Serialize(g, objp, NULL, 0)))
3163 str = strcpy(result, g->Message);
3164
3165 *res_length = strlen(str);
3166 return str;
3167} // end of json_object_grp
3168
3169void json_object_grp_clear(UDF_INIT *initid, char*, char*)
3170{
3171 PGLOBAL g = (PGLOBAL)initid->ptr;
3172
3173 PlugSubSet(g, g->Sarea, g->Sarea_Size);
3174 g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB);
3175 g->N = GetJsonGroupSize();
3176} // end of json_object_grp_clear
3177
3178void json_object_grp_deinit(UDF_INIT* initid)
3179{
3180 JsonFreeMem((PGLOBAL)initid->ptr);
3181} // end of json_object_grp_deinit
3182
3183/*********************************************************************************/
3184/* Merge two arrays or objects. */
3185/*********************************************************************************/
3186my_bool json_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3187{
3188 unsigned long reslen, memlen;
3189
3190 if (args->arg_count < 2) {
3191 strcpy(message, "This function must have at least 2 arguments");
3192 return true;
3193 } else if (!IsJson(args, 0)) {
3194 strcpy(message, "First argument must be a json item");
3195 return true;
3196 } else if (!IsJson(args, 1)) {
3197 strcpy(message, "Second argument must be a json item");
3198 return true;
3199 } else
3200 CalcLen(args, false, reslen, memlen, true);
3201
3202 if (!JsonInit(initid, args, message, true, reslen, memlen)) {
3203 PGLOBAL g = (PGLOBAL)initid->ptr;
3204
3205 // This is a constant function
3206 g->N = (initid->const_item) ? 1 : 0;
3207
3208 // This is to avoid double execution when using prepared statements
3209 if (IsJson(args, 0) > 1)
3210 initid->const_item = 0;
3211
3212 return false;
3213 } else
3214 return true;
3215
3216} // end of json_item_merge_init
3217
3218char *json_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
3219 unsigned long *res_length, char *is_null, char *error)
3220{
3221 char *str = NULL;
3222 PGLOBAL g = (PGLOBAL)initid->ptr;
3223
3224 if (g->Xchk) {
3225 // This constant function was recalled
3226 str = (char*)g->Xchk;
3227 goto fin;
3228 } // endif Xchk
3229
3230 if (!CheckMemory(g, initid, args, 2, false, false, true)) {
3231 PJSON top = NULL;
3232 PJVAL jvp;
3233 PJSON jsp[2] = {NULL, NULL};
3234
3235 for (int i = 0; i < 2; i++) {
3236 jvp = MakeValue(g, args, i);
3237 if (!i) top = jvp->GetJson();
3238
3239 if (jvp->GetValType() != TYPE_JAR && jvp->GetValType() != TYPE_JOB) {
3240 sprintf(g->Message, "Argument %d is not an array or object", i);
3241 PUSH_WARNING(g->Message);
3242 } else
3243 jsp[i] = jvp->GetJsp();
3244
3245 } // endfor i
3246
3247 if (jsp[0]) {
3248 if (jsp[0]->Merge(GetMemPtr(g, args, 0), jsp[1]))
3249 PUSH_WARNING(GetMemPtr(g, args, 0)->Message);
3250 else
3251 str = MakeResult(g, args, top);
3252
3253 } // endif jsp
3254
3255 } // endif CheckMemory
3256
3257 // In case of error or file, return unchanged argument
3258 if (!str)
3259 str = MakePSZ(g, args, 0);
3260
3261 if (g->N)
3262 // Keep result of constant function
3263 g->Xchk = str;
3264
3265 fin:
3266 if (!str) {
3267 *is_null = 1;
3268 *error = 1;
3269 *res_length = 0;
3270 } else
3271 *res_length = strlen(str);
3272
3273 return str;
3274} // end of json_item_merge
3275
3276void json_item_merge_deinit(UDF_INIT* initid)
3277{
3278 JsonFreeMem((PGLOBAL)initid->ptr);
3279} // end of json_item_merge_deinit
3280
3281/*********************************************************************************/
3282/* Get a Json item from a Json document. */
3283/*********************************************************************************/
3284my_bool json_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3285{
3286 unsigned long reslen, memlen, more;
3287 int n = IsJson(args, 0);
3288
3289 if (args->arg_count < 2) {
3290 strcpy(message, "This function must have at least 2 arguments");
3291 return true;
3292 } else if (!n && args->arg_type[0] != STRING_RESULT) {
3293 strcpy(message, "First argument must be a json item");
3294 return true;
3295 } else if (args->arg_type[1] != STRING_RESULT) {
3296 strcpy(message, "Second argument is not a string (jpath)");
3297 return true;
3298 } else
3299 CalcLen(args, false, reslen, memlen);
3300
3301 if (n == 2 && args->args[0]) {
3302 char fn[_MAX_PATH];
3303 long fl;
3304
3305 memcpy(fn, args->args[0], args->lengths[0]);
3306 fn[args->lengths[0]] = 0;
3307 fl = GetFileLength(fn);
3308 more = fl * 3;
3309 } else if (n != 3) {
3310 more = args->lengths[0] * 3;
3311 } else
3312 more = 0;
3313
3314 return JsonInit(initid, args, message, true, reslen, memlen, more);
3315} // end of json_get_item_init
3316
3317char *json_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
3318 unsigned long *res_length, char *is_null, char *)
3319{
3320 char *path, *str = NULL;
3321 PJSON jsp;
3322 PJVAL jvp;
3323 PJSNX jsx;
3324 PGLOBAL g = (PGLOBAL)initid->ptr;
3325
3326 if (g->N) {
3327 str = (char*)g->Activityp;
3328 goto fin;
3329 } else if (initid->const_item)
3330 g->N = 1;
3331
3332 if (!g->Xchk) {
3333 if (CheckMemory(g, initid, args, 1, true, true)) {
3334 PUSH_WARNING("CheckMemory error");
3335 goto fin;
3336 } // endif CheckMemory
3337
3338 jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
3339 jsp = jvp->GetJson();
3340
3341 if (g->Mrr) { // First argument is a constant
3342 g->Xchk = jsp;
3343 JsonMemSave(g);
3344 } // endif Mrr
3345
3346 } else
3347 jsp = (PJSON)g->Xchk;
3348
3349 path = MakePSZ(g, args, 1);
3350 jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
3351
3352 if (!jsx || jsx->SetJpath(g, path, true)) {
3353 PUSH_WARNING(g->Message);
3354 *is_null = 1;
3355 return NULL;
3356 } // endif SetJpath
3357
3358 jsx->ReadValue(g);
3359
3360 if (!jsx->GetValue()->IsNull())
3361 str = jsx->GetValue()->GetCharValue();
3362
3363 if (initid->const_item)
3364 // Keep result of constant function
3365 g->Activityp = (PACTIVITY)str;
3366
3367 fin:
3368 if (!str) {
3369 *is_null = 1;
3370 *res_length = 0;
3371 } else
3372 *res_length = strlen(str);
3373
3374 return str;
3375} // end of json_get_item
3376
3377void json_get_item_deinit(UDF_INIT* initid)
3378{
3379 JsonFreeMem((PGLOBAL)initid->ptr);
3380} // end of json_get_item_deinit
3381
3382/*********************************************************************************/
3383/* Get a string value from a Json item. */
3384/*********************************************************************************/
3385my_bool jsonget_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3386{
3387 unsigned long reslen, memlen, more = 1024;
3388 int n = IsJson(args, 0);
3389
3390 if (args->arg_count < 2) {
3391 strcpy(message, "At least 2 arguments required");
3392 return true;
3393 } else if (!n && args->arg_type[0] != STRING_RESULT) {
3394 strcpy(message, "First argument must be a json item");
3395 return true;
3396 } else if (args->arg_type[1] != STRING_RESULT) {
3397 strcpy(message, "Second argument is not a string (jpath)");
3398 return true;
3399 } else if (args->arg_count > 2) {
3400 if (args->arg_type[2] == INT_RESULT && args->args[2])
3401 more += (unsigned long)*(long long*)args->args[2];
3402 else
3403 strcpy(message, "Third argument is not an integer (memory)");
3404
3405 } // endif's
3406
3407 CalcLen(args, false, reslen, memlen);
3408//memlen += more;
3409
3410 if (n == 2 && args->args[0]) {
3411 char fn[_MAX_PATH];
3412 long fl;
3413
3414 memcpy(fn, args->args[0], args->lengths[0]);
3415 fn[args->lengths[0]] = 0;
3416 fl = GetFileLength(fn);
3417 more += fl * 3;
3418 } else if (n != 3)
3419 more += args->lengths[0] * 3;
3420
3421 return JsonInit(initid, args, message, true, reslen, memlen, more);
3422} // end of jsonget_string_init
3423
3424char *jsonget_string(UDF_INIT *initid, UDF_ARGS *args, char *result,
3425 unsigned long *res_length, char *is_null, char *)
3426{
3427 char *p, *path, *str = NULL;
3428 PJSON jsp;
3429 PJSNX jsx;
3430 PJVAL jvp;
3431 PGLOBAL g = (PGLOBAL)initid->ptr;
3432
3433 if (g->N) {
3434 str = (char*)g->Activityp;
3435 goto err;
3436 } else if (initid->const_item)
3437 g->N = 1;
3438
3439 try {
3440 if (!g->Xchk) {
3441 if (CheckMemory(g, initid, args, 1, true)) {
3442 PUSH_WARNING("CheckMemory error");
3443 goto err;
3444 } else
3445 jvp = MakeValue(g, args, 0);
3446
3447 if ((p = jvp->GetString(g))) {
3448 if (!(jsp = ParseJson(g, p, strlen(p)))) {
3449 PUSH_WARNING(g->Message);
3450 goto err;
3451 } // endif jsp
3452
3453 } else
3454 jsp = jvp->GetJson();
3455
3456 if (g->Mrr) { // First argument is a constant
3457 g->Xchk = jsp;
3458 JsonMemSave(g);
3459 } // endif Mrr
3460
3461 } else
3462 jsp = (PJSON)g->Xchk;
3463
3464 path = MakePSZ(g, args, 1);
3465 jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
3466
3467 if (!jsx || jsx->SetJpath(g, path)) {
3468 PUSH_WARNING(g->Message);
3469 goto err;
3470 } // endif SetJpath
3471
3472 jsx->ReadValue(g);
3473
3474 if (!jsx->GetValue()->IsNull())
3475 str = jsx->GetValue()->GetCharValue();
3476
3477 if (initid->const_item)
3478 // Keep result of constant function
3479 g->Activityp = (PACTIVITY)str;
3480
3481 } catch (int n) {
3482 if (trace(1))
3483 htrc("Exception %d: %s\n", n, g->Message);
3484
3485 PUSH_WARNING(g->Message);
3486 str = NULL;
3487 } catch (const char *msg) {
3488 strcpy(g->Message, msg);
3489 PUSH_WARNING(g->Message);
3490 str = NULL;
3491 } // end catch
3492
3493 err:
3494 if (!str) {
3495 *is_null = 1;
3496 *res_length = 0;
3497 } else
3498 *res_length = strlen(str);
3499
3500 return str;
3501} // end of jsonget_string
3502
3503void jsonget_string_deinit(UDF_INIT* initid)
3504{
3505 JsonFreeMem((PGLOBAL)initid->ptr);
3506} // end of jsonget_string_deinit
3507
3508/*********************************************************************************/
3509/* Get an integer value from a Json item. */
3510/*********************************************************************************/
3511my_bool jsonget_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3512{
3513 unsigned long reslen, memlen, more;
3514
3515 if (args->arg_count != 2) {
3516 strcpy(message, "This function must have 2 arguments");
3517 return true;
3518 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
3519 strcpy(message, "First argument must be a json item");
3520 return true;
3521 } else if (args->arg_type[1] != STRING_RESULT) {
3522 strcpy(message, "Second argument is not a (jpath) string");
3523 return true;
3524 } else
3525 CalcLen(args, false, reslen, memlen);
3526
3527 // TODO: calculate this
3528 more = (IsJson(args, 0) != 3) ? 1000 : 0;
3529
3530 return JsonInit(initid, args, message, true, reslen, memlen, more);
3531} // end of jsonget_int_init
3532
3533long long jsonget_int(UDF_INIT *initid, UDF_ARGS *args,
3534 char *is_null, char *error)
3535{
3536 char *p, *path;
3537 long long n;
3538 PJSON jsp;
3539 PJSNX jsx;
3540 PJVAL jvp;
3541 PGLOBAL g = (PGLOBAL)initid->ptr;
3542
3543 if (g->N) {
3544 if (!g->Activityp) {
3545 *is_null = 1;
3546 return 0LL;
3547 } else
3548 return *(long long*)g->Activityp;
3549
3550 } else if (initid->const_item)
3551 g->N = 1;
3552
3553 if (!g->Xchk) {
3554 if (CheckMemory(g, initid, args, 1, true)) {
3555 PUSH_WARNING("CheckMemory error");
3556 if (g->Mrr) *error = 1;
3557 *is_null = 1;
3558 return 0LL;
3559 } else
3560 jvp = MakeValue(g, args, 0);
3561
3562 if ((p = jvp->GetString(g))) {
3563 if (!(jsp = ParseJson(g, p, strlen(p)))) {
3564 PUSH_WARNING(g->Message);
3565 if (g->Mrr) *error = 1;
3566 *is_null = 1;
3567 return 0;
3568 } // endif jsp
3569
3570 } else
3571 jsp = jvp->GetJson();
3572
3573 if (g->Mrr) { // First argument is a constant
3574 g->Xchk = jsp;
3575 JsonMemSave(g);
3576 } // endif Mrr
3577
3578 } else
3579 jsp = (PJSON)g->Xchk;
3580
3581 path = MakePSZ(g, args, 1);
3582 jsx = JsnxNew(g, jsp, TYPE_BIGINT);
3583
3584 if (!jsx || jsx->SetJpath(g, path)) {
3585 PUSH_WARNING(g->Message);
3586 *is_null = 1;
3587 return 0;
3588 } // endif SetJpath
3589
3590 jsx->ReadValue(g);
3591
3592 if (jsx->GetValue()->IsNull()) {
3593 *is_null = 1;
3594 return 0;
3595 } // endif IsNull
3596
3597 n = jsx->GetValue()->GetBigintValue();
3598
3599 if (initid->const_item) {
3600 // Keep result of constant function
3601 long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
3602
3603 if (np) {
3604 *np = n;
3605 g->Activityp = (PACTIVITY)np;
3606 } else
3607 PUSH_WARNING(g->Message);
3608
3609 } // endif const_item
3610
3611 return n;
3612} // end of jsonget_int
3613
3614void jsonget_int_deinit(UDF_INIT* initid)
3615{
3616 JsonFreeMem((PGLOBAL)initid->ptr);
3617} // end of jsonget_int_deinit
3618
3619/*********************************************************************************/
3620/* Get a double value from a Json item. */
3621/*********************************************************************************/
3622my_bool jsonget_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3623{
3624 unsigned long reslen, memlen, more;
3625
3626 if (args->arg_count < 2) {
3627 strcpy(message, "At least 2 arguments required");
3628 return true;
3629 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
3630 strcpy(message, "First argument must be a json item");
3631 return true;
3632 } else if (args->arg_type[1] != STRING_RESULT) {
3633 strcpy(message, "Second argument is not a (jpath) string");
3634 return true;
3635 } else if (args->arg_count > 2) {
3636 if (args->arg_type[2] != INT_RESULT) {
3637 strcpy(message, "Third argument is not an integer (decimals)");
3638 return true;
3639 } else
3640 initid->decimals = (uint)*(longlong*)args->args[2];
3641
3642 } else
3643 initid->decimals = 15;
3644
3645 CalcLen(args, false, reslen, memlen);
3646
3647 // TODO: calculate this
3648 more = (IsJson(args, 0) != 3) ? 1000 : 0;
3649
3650 return JsonInit(initid, args, message, true, reslen, memlen, more);
3651} // end of jsonget_real_init
3652
3653double jsonget_real(UDF_INIT *initid, UDF_ARGS *args,
3654 char *is_null, char *error)
3655{
3656 char *p, *path;
3657 double d;
3658 PJSON jsp;
3659 PJSNX jsx;
3660 PJVAL jvp;
3661 PGLOBAL g = (PGLOBAL)initid->ptr;
3662
3663 if (g->N) {
3664 if (!g->Activityp) {
3665 *is_null = 1;
3666 return 0.0;
3667 } else
3668 return *(double*)g->Activityp;
3669
3670 } else if (initid->const_item)
3671 g->N = 1;
3672
3673 if (!g->Xchk) {
3674 if (CheckMemory(g, initid, args, 1, true)) {
3675 PUSH_WARNING("CheckMemory error");
3676 if (g->Mrr) *error = 1;
3677 *is_null = 1;
3678 return 0.0;
3679 } else
3680 jvp = MakeValue(g, args, 0);
3681
3682 if ((p = jvp->GetString(g))) {
3683 if (!(jsp = ParseJson(g, p, strlen(p)))) {
3684 PUSH_WARNING(g->Message);
3685 *is_null = 1;
3686 return 0.0;
3687 } // endif jsp
3688
3689 } else
3690 jsp = jvp->GetJson();
3691
3692 if (g->Mrr) { // First argument is a constant
3693 g->Xchk = jsp;
3694 JsonMemSave(g);
3695 } // endif Mrr
3696
3697 } else
3698 jsp = (PJSON)g->Xchk;
3699
3700 path = MakePSZ(g, args, 1);
3701 jsx = JsnxNew(g, jsp, TYPE_DOUBLE);
3702
3703 if (!jsx || jsx->SetJpath(g, path)) {
3704 PUSH_WARNING(g->Message);
3705 *is_null = 1;
3706 return 0.0;
3707 } // endif SetJpath
3708
3709 jsx->ReadValue(g);
3710
3711 if (jsx->GetValue()->IsNull()) {
3712 *is_null = 1;
3713 return 0.0;
3714 } // endif IsNull
3715
3716 d = jsx->GetValue()->GetFloatValue();
3717
3718 if (initid->const_item) {
3719 // Keep result of constant function
3720 double *dp;
3721
3722 if ((dp = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
3723 *dp = d;
3724 g->Activityp = (PACTIVITY)dp;
3725 } else {
3726 PUSH_WARNING(g->Message);
3727 *is_null = 1;
3728 return 0.0;
3729 } // endif dp
3730
3731 } // endif const_item
3732
3733 return d;
3734} // end of jsonget_real
3735
3736void jsonget_real_deinit(UDF_INIT* initid)
3737{
3738 JsonFreeMem((PGLOBAL)initid->ptr);
3739} // end of jsonget_real_deinit
3740
3741/*********************************************************************************/
3742/* Locate a value in a Json tree. */
3743/*********************************************************************************/
3744my_bool jsonlocate_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3745{
3746 unsigned long reslen, memlen, more = 1000;
3747
3748 if (args->arg_count < 2) {
3749 strcpy(message, "At least 2 arguments required");
3750 return true;
3751 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
3752 strcpy(message, "First argument must be a json item");
3753 return true;
3754 } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
3755 strcpy(message, "Third argument is not an integer (rank)");
3756 return true;
3757 } else if (args->arg_count > 3)
3758 if (args->arg_type[3] != INT_RESULT) {
3759 strcpy(message, "Fourth argument is not an integer (memory)");
3760 return true;
3761 } else
3762 more += (ulong)*(longlong*)args->args[2];
3763
3764 CalcLen(args, false, reslen, memlen);
3765
3766 // TODO: calculate this
3767 if (IsJson(args, 0) == 3)
3768 more = 0;
3769
3770 return JsonInit(initid, args, message, true, reslen, memlen, more);
3771} // end of jsonlocate_init
3772
3773char *jsonlocate(UDF_INIT *initid, UDF_ARGS *args, char *result,
3774 unsigned long *res_length, char *is_null, char *error)
3775{
3776 char *path = NULL;
3777 int k;
3778 PJVAL jvp, jvp2;
3779 PJSON jsp;
3780 PJSNX jsx;
3781 PGLOBAL g = (PGLOBAL)initid->ptr;
3782
3783 if (g->N) {
3784 if (g->Activityp) {
3785 path = (char*)g->Activityp;
3786 *res_length = strlen(path);
3787 return path;
3788 } else {
3789 *res_length = 0;
3790 *is_null = 1;
3791 return NULL;
3792 } // endif Activityp
3793
3794 } else if (initid->const_item)
3795 g->N = 1;
3796
3797 try {
3798 if (!g->Xchk) {
3799 if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
3800 PUSH_WARNING("CheckMemory error");
3801 *error = 1;
3802 goto err;
3803 } else
3804 jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
3805
3806 //if ((p = jvp->GetString(g))) {
3807 // if (!(jsp = ParseJson(g, p, strlen(p)))) {
3808 // PUSH_WARNING(g->Message);
3809 // goto err;
3810 // } // endif jsp
3811 //} else
3812 // jsp = jvp->GetJson();
3813
3814 if (!(jsp = jvp->GetJson())) {
3815 PUSH_WARNING("First argument is not a valid JSON item");
3816 goto err;
3817 } // endif jsp
3818
3819 if (g->Mrr) { // First argument is a constant
3820 g->Xchk = jsp;
3821 JsonMemSave(g);
3822 } // endif Mrr
3823
3824 } else
3825 jsp = (PJSON)g->Xchk;
3826
3827 // The item to locate
3828 jvp2 = MakeValue(g, args, 1);
3829
3830 k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
3831
3832 jsx = new(g) JSNX(g, jsp, TYPE_STRING);
3833 path = jsx->Locate(g, jsp, jvp2, k);
3834
3835 if (initid->const_item)
3836 // Keep result of constant function
3837 g->Activityp = (PACTIVITY)path;
3838
3839 } catch (int n) {
3840 if (trace(1))
3841 htrc("Exception %d: %s\n", n, g->Message);
3842
3843 PUSH_WARNING(g->Message);
3844 *error = 1;
3845 path = NULL;
3846 } catch (const char *msg) {
3847 strcpy(g->Message, msg);
3848 PUSH_WARNING(g->Message);
3849 *error = 1;
3850 path = NULL;
3851 } // end catch
3852
3853 err:
3854 if (!path) {
3855 *res_length = 0;
3856 *is_null = 1;
3857 } else
3858 *res_length = strlen(path);
3859
3860 return path;
3861} // end of jsonlocate
3862
3863void jsonlocate_deinit(UDF_INIT* initid)
3864{
3865 JsonFreeMem((PGLOBAL)initid->ptr);
3866} // end of jsonlocate_deinit
3867
3868/*********************************************************************************/
3869/* Locate all occurences of a value in a Json tree. */
3870/*********************************************************************************/
3871my_bool json_locate_all_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3872{
3873 unsigned long reslen, memlen, more = 1000;
3874
3875 if (args->arg_count < 2) {
3876 strcpy(message, "At least 2 arguments required");
3877 return true;
3878 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
3879 strcpy(message, "First argument must be a json item");
3880 return true;
3881 } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
3882 strcpy(message, "Third argument is not an integer (Depth)");
3883 return true;
3884 } else if (args->arg_count > 3)
3885 if (args->arg_type[3] != INT_RESULT) {
3886 strcpy(message, "Fourth argument is not an integer (memory)");
3887 return true;
3888 } else
3889 more += (ulong)*(longlong*)args->args[2];
3890
3891 CalcLen(args, false, reslen, memlen);
3892
3893 // TODO: calculate this
3894 if (IsJson(args, 0) == 3)
3895 more = 0;
3896
3897 return JsonInit(initid, args, message, true, reslen, memlen, more);
3898} // end of json_locate_all_init
3899
3900char *json_locate_all(UDF_INIT *initid, UDF_ARGS *args, char *result,
3901 unsigned long *res_length, char *is_null, char *error)
3902{
3903 char *p, *path = NULL;
3904 int mx = 10;
3905 PJVAL jvp, jvp2;
3906 PJSON jsp;
3907 PJSNX jsx;
3908 PGLOBAL g = (PGLOBAL)initid->ptr;
3909
3910 if (g->N) {
3911 if (g->Activityp) {
3912 path = (char*)g->Activityp;
3913 *res_length = strlen(path);
3914 return path;
3915 } else {
3916 *error = 1;
3917 *res_length = 0;
3918 *is_null = 1;
3919 return NULL;
3920 } // endif Activityp
3921
3922 } else if (initid->const_item)
3923 g->N = 1;
3924
3925 try {
3926 if (!g->Xchk) {
3927 if (CheckMemory(g, initid, args, 1, true)) {
3928 PUSH_WARNING("CheckMemory error");
3929 *error = 1;
3930 goto err;
3931 } else
3932 jvp = MakeValue(g, args, 0);
3933
3934 if ((p = jvp->GetString(g))) {
3935 if (!(jsp = ParseJson(g, p, strlen(p)))) {
3936 PUSH_WARNING(g->Message);
3937 goto err;
3938 } // endif jsp
3939
3940 } else
3941 jsp = jvp->GetJson();
3942
3943 if (g->Mrr) { // First argument is a constant
3944 g->Xchk = jsp;
3945 JsonMemSave(g);
3946 } // endif Mrr
3947
3948 } else
3949 jsp = (PJSON)g->Xchk;
3950
3951 // The item to locate
3952 jvp2 = MakeValue(g, args, 1);
3953
3954 if (args->arg_count > 2)
3955 mx = (int)*(long long*)args->args[2];
3956
3957 jsx = new(g) JSNX(g, jsp, TYPE_STRING);
3958 path = jsx->LocateAll(g, jsp, jvp2, mx);
3959
3960 if (initid->const_item)
3961 // Keep result of constant function
3962 g->Activityp = (PACTIVITY)path;
3963
3964 } catch (int n) {
3965 if (trace(1))
3966 htrc("Exception %d: %s\n", n, g->Message);
3967
3968 PUSH_WARNING(g->Message);
3969 *error = 1;
3970 path = NULL;
3971 } catch (const char *msg) {
3972 strcpy(g->Message, msg);
3973 PUSH_WARNING(g->Message);
3974 *error = 1;
3975 path = NULL;
3976 } // end catch
3977
3978 err:
3979 if (!path) {
3980 *res_length = 0;
3981 *is_null = 1;
3982 } else
3983 *res_length = strlen(path);
3984
3985 return path;
3986} // end of json_locate_all
3987
3988void json_locate_all_deinit(UDF_INIT* initid)
3989{
3990 JsonFreeMem((PGLOBAL)initid->ptr);
3991} // end of json_locate_all_deinit
3992
3993/*********************************************************************************/
3994/* Check whether the document contains a value or item. */
3995/*********************************************************************************/
3996my_bool jsoncontains_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
3997{
3998 unsigned long reslen, memlen, more = 1024;
3999 int n = IsJson(args, 0);
4000
4001 if (args->arg_count < 2) {
4002 strcpy(message, "At least 2 arguments required");
4003 return true;
4004 } else if (!n && args->arg_type[0] != STRING_RESULT) {
4005 strcpy(message, "First argument must be a json item");
4006 return true;
4007 } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
4008 strcpy(message, "Third argument is not an integer (index)");
4009 return true;
4010 } else if (args->arg_count > 3) {
4011 if (args->arg_type[3] == INT_RESULT && args->args[3])
4012 more += (unsigned long)*(long long*)args->args[3];
4013 else
4014 strcpy(message, "Fourth argument is not an integer (memory)");
4015
4016 } // endif's
4017
4018 CalcLen(args, false, reslen, memlen);
4019//memlen += more;
4020
4021 // TODO: calculate this
4022 more += (IsJson(args, 0) != 3 ? 1000 : 0);
4023
4024 return JsonInit(initid, args, message, false, reslen, memlen, more);
4025} // end of jsoncontains_init
4026
4027long long jsoncontains(UDF_INIT *initid, UDF_ARGS *args, char *result,
4028 unsigned long *res_length, char *is_null, char *error)
4029{
4030 char *p __attribute__((unused)), res[256];
4031 long long n;
4032 unsigned long reslen;
4033
4034 *is_null = 0;
4035 p = jsonlocate(initid, args, res, &reslen, is_null, error);
4036 n = (*is_null) ? 0LL : 1LL;
4037 return n;
4038} // end of jsoncontains
4039
4040void jsoncontains_deinit(UDF_INIT* initid)
4041{
4042 JsonFreeMem((PGLOBAL)initid->ptr);
4043} // end of jsoncontains_deinit
4044
4045/*********************************************************************************/
4046/* Check whether the document contains a path. */
4047/*********************************************************************************/
4048my_bool jsoncontains_path_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4049{
4050 unsigned long reslen, memlen, more = 1024;
4051 int n = IsJson(args, 0);
4052
4053 if (args->arg_count < 2) {
4054 strcpy(message, "At least 2 arguments required");
4055 return true;
4056 } else if (!n && args->arg_type[0] != STRING_RESULT) {
4057 strcpy(message, "First argument must be a json item");
4058 return true;
4059 } else if (args->arg_type[1] != STRING_RESULT) {
4060 strcpy(message, "Second argument is not a string (path)");
4061 return true;
4062 } else if (args->arg_count > 2) {
4063 if (args->arg_type[2] == INT_RESULT && args->args[2])
4064 more += (unsigned long)*(long long*)args->args[2];
4065 else
4066 strcpy(message, "Third argument is not an integer (memory)");
4067
4068 } // endif's
4069
4070 CalcLen(args, false, reslen, memlen);
4071//memlen += more;
4072
4073 // TODO: calculate this
4074 more += (IsJson(args, 0) != 3 ? 1000 : 0);
4075
4076 return JsonInit(initid, args, message, true, reslen, memlen, more);
4077} // end of jsoncontains_path_init
4078
4079long long jsoncontains_path(UDF_INIT *initid, UDF_ARGS *args, char *result,
4080 unsigned long *res_length, char *is_null, char *error)
4081{
4082 char *p, *path;
4083 long long n;
4084 PJSON jsp;
4085 PJSNX jsx;
4086 PJVAL jvp;
4087 PGLOBAL g = (PGLOBAL)initid->ptr;
4088
4089 if (g->N) {
4090 if (!g->Activityp) {
4091 *is_null = 1;
4092 return 0LL;
4093 } else
4094 return *(long long*)g->Activityp;
4095
4096 } else if (initid->const_item)
4097 g->N = 1;
4098
4099 if (!g->Xchk) {
4100 if (CheckMemory(g, initid, args, 1, true)) {
4101 PUSH_WARNING("CheckMemory error");
4102 goto err;
4103 } else
4104 jvp = MakeValue(g, args, 0);
4105
4106 if ((p = jvp->GetString(g))) {
4107 if (!(jsp = ParseJson(g, p, strlen(p)))) {
4108 PUSH_WARNING(g->Message);
4109 goto err;
4110 } // endif jsp
4111
4112 } else
4113 jsp = jvp->GetJson();
4114
4115 if (g->Mrr) { // First argument is a constant
4116 g->Xchk = jsp;
4117 JsonMemSave(g);
4118 } // endif Mrr
4119
4120 } else
4121 jsp = (PJSON)g->Xchk;
4122
4123 path = MakePSZ(g, args, 1);
4124 jsx = JsnxNew(g, jsp, TYPE_BIGINT);
4125
4126 if (!jsx || jsx->SetJpath(g, path)) {
4127 PUSH_WARNING(g->Message);
4128 goto err;
4129 } // endif SetJpath
4130
4131 n = (jsx->CheckPath(g)) ? 1LL : 0LL;
4132
4133 if (initid->const_item) {
4134 // Keep result of constant function
4135 long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
4136
4137 if (np) {
4138 *np = n;
4139 g->Activityp = (PACTIVITY)np;
4140 } else
4141 PUSH_WARNING(g->Message);
4142
4143 } // endif const_item
4144
4145 return n;
4146
4147 err:
4148 if (g->Mrr) *error = 1;
4149 *is_null = 1;
4150 return 0LL;
4151} // end of jsoncontains_path
4152
4153void jsoncontains_path_deinit(UDF_INIT* initid)
4154{
4155 JsonFreeMem((PGLOBAL)initid->ptr);
4156} // end of jsoncontains_path_deinit
4157
4158/*********************************************************************************/
4159/* This function is used by the json_set/insert/update_item functions. */
4160/*********************************************************************************/
4161char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
4162 unsigned long *res_length, char *is_null, char *error)
4163{
4164 char *p, *path, *str = NULL;
4165 int w;
4166 my_bool b = true;
4167 PJSON jsp;
4168 PJSNX jsx;
4169 PJVAL jvp;
4170 PGLOBAL g = (PGLOBAL)initid->ptr;
4171 PGLOBAL gb = GetMemPtr(g, args, 0);
4172
4173 if (g->Alchecked) {
4174 str = (char*)g->Activityp;
4175 goto fin;
4176 } else if (g->N)
4177 g->Alchecked = 1;
4178
4179 if (!strcmp(result, "$set"))
4180 w = 0;
4181 else if (!strcmp(result, "$insert"))
4182 w = 1;
4183 else if (!strcmp(result, "$update"))
4184 w = 2;
4185 else {
4186 PUSH_WARNING("Logical error, please contact CONNECT developer");
4187 goto fin;
4188 } // endelse
4189
4190 try {
4191 if (!g->Xchk) {
4192 if (CheckMemory(g, initid, args, 1, true, false, true)) {
4193 PUSH_WARNING("CheckMemory error");
4194 throw 1;
4195 } else
4196 jvp = MakeValue(g, args, 0);
4197
4198 if ((p = jvp->GetString(g))) {
4199 if (!(jsp = ParseJson(g, p, strlen(p)))) {
4200 throw 2;
4201 } // endif jsp
4202
4203 } else
4204 jsp = jvp->GetJson();
4205
4206 if (g->Mrr) { // First argument is a constant
4207 g->Xchk = jsp;
4208 JsonMemSave(g);
4209 } // endif Mrr
4210
4211 } else
4212 jsp = (PJSON)g->Xchk;
4213
4214 jsx = new(g)JSNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
4215
4216 for (uint i = 1; i + 1 < args->arg_count; i += 2) {
4217 jvp = MakeValue(gb, args, i);
4218 path = MakePSZ(g, args, i + 1);
4219
4220 if (jsx->SetJpath(g, path, false)) {
4221 PUSH_WARNING(g->Message);
4222 continue;
4223 } // endif SetJpath
4224
4225 if (w) {
4226 jsx->ReadValue(g);
4227 b = jsx->GetValue()->IsNull();
4228 b = (w == 1) ? b : !b;
4229 } // endif w
4230
4231 if (b && jsx->WriteValue(gb, jvp))
4232 PUSH_WARNING(g->Message);
4233
4234 } // endfor i
4235
4236 // In case of error or file, return unchanged argument
4237 if (!(str = MakeResult(g, args, jsp, INT_MAX32)))
4238 str = MakePSZ(g, args, 0);
4239
4240 if (g->N)
4241 // Keep result of constant function
4242 g->Activityp = (PACTIVITY)str;
4243
4244 } catch (int n) {
4245 if (trace(1))
4246 htrc("Exception %d: %s\n", n, g->Message);
4247
4248 PUSH_WARNING(g->Message);
4249 str = NULL;
4250 } catch (const char *msg) {
4251 strcpy(g->Message, msg);
4252 PUSH_WARNING(g->Message);
4253 str = NULL;
4254 } // end catch
4255
4256fin:
4257 if (!str) {
4258 *is_null = 1;
4259 *res_length = 0;
4260 } else
4261 *res_length = strlen(str);
4262
4263 return str;
4264} // end of handle_item
4265
4266/*********************************************************************************/
4267/* Set Json items of a Json document according to path. */
4268/*********************************************************************************/
4269my_bool json_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4270{
4271 unsigned long reslen, memlen, more = 0;
4272 int n = IsJson(args, 0);
4273
4274 if (!(args->arg_count % 2)) {
4275 strcpy(message, "This function must have an odd number of arguments");
4276 return true;
4277 } else if (!n && args->arg_type[0] != STRING_RESULT) {
4278 strcpy(message, "First argument must be a json item");
4279 return true;
4280 } else
4281 CalcLen(args, false, reslen, memlen);
4282
4283 if (n == 2 && args->args[0]) {
4284 char fn[_MAX_PATH];
4285 long fl;
4286
4287 memcpy(fn, args->args[0], args->lengths[0]);
4288 fn[args->lengths[0]] = 0;
4289 fl = GetFileLength(fn);
4290 more += fl * 3;
4291 } else if (n != 3)
4292 more += args->lengths[0] * 3;
4293
4294 if (!JsonInit(initid, args, message, true, reslen, memlen, more)) {
4295 PGLOBAL g = (PGLOBAL)initid->ptr;
4296
4297 // This is a constant function
4298 g->N = (initid->const_item) ? 1 : 0;
4299
4300 // This is to avoid double execution when using prepared statements
4301 if (IsJson(args, 0) > 1)
4302 initid->const_item = 0;
4303
4304 g->Alchecked = 0;
4305 return false;
4306 } else
4307 return true;
4308
4309} // end of json_set_item_init
4310
4311char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
4312 unsigned long *res_length, char *is_null, char *p)
4313{
4314 strcpy(result, "$set");
4315 return handle_item(initid, args, result, res_length, is_null, p);
4316} // end of json_set_item
4317
4318void json_set_item_deinit(UDF_INIT* initid)
4319{
4320 JsonFreeMem((PGLOBAL)initid->ptr);
4321} // end of json_set_item_deinit
4322
4323/*********************************************************************************/
4324/* Insert Json items of a Json document according to path. */
4325/*********************************************************************************/
4326my_bool json_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4327{
4328 return json_set_item_init(initid, args, message);
4329} // end of json_insert_item_init
4330
4331char *json_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
4332 unsigned long *res_length, char *is_null, char *p)
4333{
4334 strcpy(result, "$insert");
4335 return handle_item(initid, args, result, res_length, is_null, p);
4336} // end of json_insert_item
4337
4338void json_insert_item_deinit(UDF_INIT* initid)
4339{
4340 JsonFreeMem((PGLOBAL)initid->ptr);
4341} // end of json_insert_item_deinit
4342
4343/*********************************************************************************/
4344/* Update Json items of a Json document according to path. */
4345/*********************************************************************************/
4346my_bool json_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4347{
4348 return json_set_item_init(initid, args, message);
4349} // end of json_update_item_init
4350
4351char *json_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
4352 unsigned long *res_length, char *is_null, char *p)
4353{
4354 strcpy(result, "$update");
4355 return handle_item(initid, args, result, res_length, is_null, p);
4356} // end of json_update_item
4357
4358void json_update_item_deinit(UDF_INIT* initid)
4359{
4360 JsonFreeMem((PGLOBAL)initid->ptr);
4361} // end of json_update_item_deinit
4362
4363/*********************************************************************************/
4364/* Returns a json file as a json string. */
4365/*********************************************************************************/
4366my_bool json_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4367{
4368 unsigned long reslen, memlen, fl, more = 1024;
4369
4370 if (args->arg_count < 1 || args->arg_count > 4) {
4371 strcpy(message, "This function only accepts 1 to 4 arguments");
4372 return true;
4373 } else if (args->arg_type[0] != STRING_RESULT) {
4374 strcpy(message, "First argument must be a string (file name)");
4375 return true;
4376 } // endif's args[0]
4377
4378 for (unsigned int i = 1; i < args->arg_count; i++) {
4379 if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
4380 sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i);
4381 return true;
4382 } // endif arg_type
4383
4384 // Take care of eventual memory argument
4385 if (args->arg_type[i] == INT_RESULT && args->args[i])
4386 more += (ulong)*(longlong*)args->args[i];
4387
4388 } // endfor i
4389
4390 initid->maybe_null = 1;
4391 CalcLen(args, false, reslen, memlen);
4392
4393 if (args->args[0])
4394 fl = GetFileLength(args->args[0]);
4395 else
4396 fl = 100; // What can be done here?
4397
4398 reslen += fl;
4399
4400 if (initid->const_item)
4401 more += fl;
4402
4403 if (args->arg_count > 1)
4404 more += fl * M;
4405
4406 memlen += more;
4407 return JsonInit(initid, args, message, true, reslen, memlen);
4408} // end of json_file_init
4409
4410char *json_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
4411 unsigned long *res_length, char *is_null, char *error)
4412{
4413 char *str, *fn;
4414 PGLOBAL g = (PGLOBAL)initid->ptr;
4415
4416 if (g->N) {
4417 str = (char*)g->Xchk;
4418 goto fin;
4419 } else if (initid->const_item)
4420 g->N = 1;
4421
4422 PlugSubSet(g, g->Sarea, g->Sarea_Size);
4423 fn = MakePSZ(g, args, 0);
4424
4425 if (args->arg_count > 1) {
4426 int len, pretty, pty = 3;
4427 PJSON jsp;
4428 PJVAL jvp = NULL;
4429
4430 pretty = (args->arg_type[1] == INT_RESULT) ? (int)*(longlong*)args->args[1]
4431 : (args->arg_count > 2 && args->arg_type[2] == INT_RESULT)
4432 ? (int)*(longlong*)args->args[2] : 3;
4433
4434 /*******************************************************************************/
4435 /* Parse the json file and allocate its tree structure. */
4436 /*******************************************************************************/
4437 if (!(jsp = ParseJsonFile(g, fn, &pty, len))) {
4438 PUSH_WARNING(g->Message);
4439 str = NULL;
4440 goto fin;
4441 } // endif jsp
4442
4443 if (pty == 3)
4444 PUSH_WARNING("File pretty format cannot be determined");
4445 else if (pretty != 3 && pty != pretty)
4446 PUSH_WARNING("File pretty format doesn't match the specified pretty value");
4447 else if (pretty == 3)
4448 pretty = pty;
4449
4450 // Check whether a path was specified
4451 if (CheckPath(g, args, jsp, jvp, 1)) {
4452 PUSH_WARNING(g->Message);
4453 str = NULL;
4454 goto fin;
4455 } else if (jvp)
4456 jsp = jvp->GetJson();
4457
4458 if (!(str = Serialize(g, jsp, NULL, 0)))
4459 PUSH_WARNING(g->Message);
4460
4461 } else
4462 if (!(str = GetJsonFile(g, fn)))
4463 PUSH_WARNING(g->Message);
4464
4465 if (initid->const_item)
4466 // Keep result of constant function
4467 g->Xchk = str;
4468
4469 fin:
4470 if (!str) {
4471 *res_length = 0;
4472 *is_null = 1;
4473 } else
4474 *res_length = strlen(str);
4475
4476 return str;
4477} // end of json_file
4478
4479void json_file_deinit(UDF_INIT* initid)
4480{
4481 JsonFreeMem((PGLOBAL)initid->ptr);
4482} // end of json_file_deinit
4483
4484/*********************************************************************************/
4485/* Make a json file from a json item. */
4486/*********************************************************************************/
4487my_bool jfile_make_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4488{
4489 unsigned long reslen, memlen;
4490
4491 if (args->arg_count < 1 || args->arg_count > 3) {
4492 strcpy(message, "Wrong number of arguments");
4493 return true;
4494 } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
4495 strcpy(message, "First argument must be a json item");
4496 return true;
4497 } // endif
4498
4499 CalcLen(args, false, reslen, memlen);
4500 return JsonInit(initid, args, message, true, reslen, memlen);
4501} // end of jfile_make_init
4502
4503char *jfile_make(UDF_INIT *initid, UDF_ARGS *args, char *result,
4504 unsigned long *res_length, char *is_null, char *)
4505{
4506 char *p, *str = NULL, *fn = NULL;
4507 int n, pretty = 2;
4508 PJSON jsp;
4509 PJVAL jvp;
4510 PGLOBAL g = (PGLOBAL)initid->ptr;
4511
4512 if (g->N) {
4513 str = (char*)g->Activityp;
4514 goto fin;
4515 } else if (initid->const_item)
4516 g->N = 1;
4517
4518 if ((n = IsJson(args, 0)) == 3) {
4519 // Get default file name and pretty
4520 PBSON bsp = (PBSON)args->args[0];
4521
4522 fn = bsp->Filename;
4523 pretty = bsp->Pretty;
4524 } else if (n == 2)
4525 fn = args->args[0];
4526
4527 if (!g->Xchk) {
4528 if (CheckMemory(g, initid, args, 1, true)) {
4529 PUSH_WARNING("CheckMemory error");
4530 goto fin;
4531 } else
4532 jvp = MakeValue(g, args, 0);
4533
4534 if ((p = jvp->GetString(g))) {
4535 if (!strchr("[{ \t\r\n", *p)) {
4536 // Is this a file name?
4537 if (!(p = GetJsonFile(g, p))) {
4538 PUSH_WARNING(g->Message);
4539 goto fin;
4540 } else
4541 fn = jvp->GetString(g);
4542
4543 } // endif p
4544
4545 if (!(jsp = ParseJson(g, p, strlen(p)))) {
4546 PUSH_WARNING(g->Message);
4547 goto fin;
4548 } // endif jsp
4549
4550 jvp->SetValue(jsp);
4551 } // endif p
4552
4553 if (g->Mrr) { // First argument is a constant
4554 g->Xchk = jvp;
4555 JsonMemSave(g);
4556 } // endif Mrr
4557
4558 } else
4559 jvp = (PJVAL)g->Xchk;
4560
4561 for (uint i = 1; i < args->arg_count; i++)
4562 switch (args->arg_type[i]) {
4563 case STRING_RESULT:
4564 fn = MakePSZ(g, args, i);
4565 break;
4566 case INT_RESULT:
4567 pretty = (int)*(longlong*)args->args[i];
4568 break;
4569 default:
4570 PUSH_WARNING("Unexpected argument type in jfile_make");
4571 } // endswitch arg_type
4572
4573 if (fn) {
4574 if (!Serialize(g, jvp->GetJson(), fn, pretty))
4575 PUSH_WARNING(g->Message);
4576 } else
4577 PUSH_WARNING("Missing file name");
4578
4579 str= fn;
4580
4581 if (initid->const_item)
4582 // Keep result of constant function
4583 g->Activityp = (PACTIVITY)str;
4584
4585 fin:
4586 if (!str) {
4587 *res_length = 0;
4588 *is_null = 1;
4589 } else
4590 *res_length = strlen(str);
4591
4592 return str;
4593} // end of jfile_make
4594
4595void jfile_make_deinit(UDF_INIT* initid)
4596{
4597 JsonFreeMem((PGLOBAL)initid->ptr);
4598} // end of jfile_make_deinit
4599
4600/*********************************************************************************/
4601/* Make and return a binary Json array containing all the parameters. */
4602/*********************************************************************************/
4603my_bool jbin_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4604{
4605 unsigned long reslen, memlen;
4606
4607 CalcLen(args, false, reslen, memlen);
4608 return JsonInit(initid, args, message, true, reslen, memlen);
4609} // end of jbin_array_init
4610
4611char *jbin_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
4612 unsigned long *res_length, char *is_null, char *error)
4613{
4614 PGLOBAL g = (PGLOBAL)initid->ptr;
4615 PBSON bsp = (PBSON)g->Xchk;
4616
4617 if (!bsp || bsp->Changed) {
4618 if (!CheckMemory(g, initid, args, args->arg_count, false)) {
4619 PJAR arp;
4620
4621 if ((arp = (PJAR)JsonNew(g, TYPE_JAR)) &&
4622 (bsp = JbinAlloc(g, args, initid->max_length, arp))) {
4623 strcat(bsp->Msg, " array");
4624
4625 for (uint i = 0; i < args->arg_count; i++)
4626 arp->AddValue(g, MakeValue(g, args, i));
4627
4628 arp->InitArray(g);
4629 } // endif arp && bsp
4630
4631 } else
4632 bsp = NULL;
4633
4634 if (!bsp && (bsp = JbinAlloc(g, args, initid->max_length, NULL)))
4635 strncpy(bsp->Msg, g->Message, 139);
4636
4637 // Keep result of constant function
4638 g->Xchk = (initid->const_item) ? bsp : NULL;
4639 } // endif bsp
4640
4641 if (!bsp) {
4642 *is_null = 1;
4643 *error = 1;
4644 *res_length = 0;
4645 } else
4646 *res_length = sizeof(BSON);
4647
4648 return (char*)bsp;
4649} // end of jbin_array
4650
4651void jbin_array_deinit(UDF_INIT* initid)
4652{
4653 JsonFreeMem((PGLOBAL)initid->ptr);
4654} // end of jbin_array_deinit
4655
4656/*********************************************************************************/
4657/* Add one or several values to a Json array. */
4658/*********************************************************************************/
4659my_bool jbin_array_add_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4660{
4661 unsigned long reslen, memlen;
4662
4663 if (args->arg_count < 2) {
4664 strcpy(message, "This function must have at least 2 arguments");
4665 return true;
4666 } else
4667 CalcLen(args, false, reslen, memlen);
4668
4669 return JsonInit(initid, args, message, true, reslen, memlen);
4670} // end of jbin_array_add_values_init
4671
4672char *jbin_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
4673 unsigned long *res_length, char *is_null, char *error)
4674{
4675 PGLOBAL g = (PGLOBAL)initid->ptr;
4676 PBSON bsp = (PBSON)g->Xchk;
4677
4678 if (!bsp || bsp->Changed) {
4679 if (!CheckMemory(g, initid, args, args->arg_count, true)) {
4680 PJSON top;
4681 PJAR arp;
4682 PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top);
4683 PGLOBAL gb = GetMemPtr(g, args, 0);
4684
4685 if (jvp->GetValType() != TYPE_JAR) {
4686 if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
4687 arp->AddValue(gb, jvp);
4688 top = arp;
4689 } // endif arp
4690
4691 } else
4692 arp = jvp->GetArray();
4693
4694 for (uint i = 1; i < args->arg_count; i++)
4695 arp->AddValue(gb, MakeValue(gb, args, i));
4696
4697 arp->InitArray(gb);
4698
4699 if ((bsp = JbinAlloc(g, args, initid->max_length, top))) {
4700 strcat(bsp->Msg, " array");
4701 bsp->Jsp = arp;
4702 } // endif bsp
4703
4704 } else
4705 if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
4706 strncpy(bsp->Msg, g->Message, BMX);
4707
4708 // Keep result of constant function
4709 g->Xchk = (initid->const_item) ? bsp : NULL;
4710 } // endif bsp
4711
4712 if (!bsp) {
4713 *is_null = 1;
4714 *error = 1;
4715 *res_length = 0;
4716 } else
4717 *res_length = sizeof(BSON);
4718
4719 return (char*)bsp;
4720} // end of jbin_array_add_values
4721
4722void jbin_array_add_values_deinit(UDF_INIT* initid)
4723{
4724 JsonFreeMem((PGLOBAL)initid->ptr);
4725} // end of jbin_array_add_values_deinit
4726
4727/*********************************************************************************/
4728/* Add one value to a Json array. */
4729/*********************************************************************************/
4730my_bool jbin_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4731{
4732 unsigned long reslen, memlen;
4733
4734 if (args->arg_count < 2) {
4735 strcpy(message, "This function must have at least 2 arguments");
4736 return true;
4737 //} else if (!IsJson(args, 0)) {
4738 // strcpy(message, "First argument must be a json item");
4739 // return true;
4740 } else
4741 CalcLen(args, false, reslen, memlen, true);
4742
4743 return JsonInit(initid, args, message, true, reslen, memlen);
4744} // end of jbin_array_add_init
4745
4746char *jbin_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
4747 unsigned long *res_length, char *is_null, char *error)
4748{
4749 int n = 2;
4750 PJSON top = NULL;
4751 PGLOBAL g = (PGLOBAL)initid->ptr;
4752 PBSON bsp = (PBSON)g->Xchk;
4753
4754 if (bsp && !bsp->Changed) {
4755 // This constant function was recalled
4756 *res_length = sizeof(BSON);
4757 return (char*)bsp;
4758 } // endif bsp
4759
4760 if (!CheckMemory(g, initid, args, 2, false, false, true)) {
4761 int *x = NULL;
4762 uint n = 2;
4763// PJSON jsp;
4764 PJVAL jvp;
4765 PJAR arp;
4766
4767 jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
4768 // jsp = jvp->GetJson();
4769 x = GetIntArgPtr(g, args, n);
4770
4771 if (CheckPath(g, args, top, jvp, n))
4772 PUSH_WARNING(g->Message);
4773 else if (jvp) {
4774 PGLOBAL gb = GetMemPtr(g, args, 0);
4775
4776 if (jvp->GetValType() != TYPE_JAR) {
4777 if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
4778 arp->AddValue(gb, (PJVAL)JvalNew(gb, TYPE_JVAL, jvp));
4779 jvp->SetValue(arp);
4780
4781 if (!top)
4782 top = arp;
4783
4784 } // endif arp
4785
4786 } else
4787 arp = jvp->GetArray();
4788
4789 arp->AddValue(gb, MakeValue(gb, args, 1), x);
4790 arp->InitArray(gb);
4791 } else {
4792 PUSH_WARNING("First argument target is not an array");
4793// if (g->Mrr) *error = 1; (only if no path)
4794 } // endif jvp
4795
4796 } // endif CheckMemory
4797
4798 // In case of error unchanged argument will be returned
4799 bsp = MakeBinResult(g, args, top, initid->max_length, n);
4800
4801 if (initid->const_item)
4802 // Keep result of constant function
4803 g->Xchk = bsp;
4804
4805 if (!bsp) {
4806 *is_null = 1;
4807 *error = 1;
4808 *res_length = 0;
4809 } else
4810 *res_length = sizeof(BSON);
4811
4812 return (char*)bsp;
4813} // end of jbin_array_add
4814
4815void jbin_array_add_deinit(UDF_INIT* initid)
4816{
4817 JsonFreeMem((PGLOBAL)initid->ptr);
4818} // end of jbin_array_add_deinit
4819
4820/*********************************************************************************/
4821/* Delete a value from a Json array. */
4822/*********************************************************************************/
4823my_bool jbin_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4824{
4825 unsigned long reslen, memlen;
4826
4827 if (args->arg_count < 2) {
4828 strcpy(message, "This function must have at least 2 arguments");
4829 return true;
4830 } else
4831 CalcLen(args, false, reslen, memlen, true);
4832
4833 return JsonInit(initid, args, message, true, reslen, memlen);
4834 } // end of jbin_array_delete_init
4835
4836char *jbin_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
4837 unsigned long *res_length, char *is_null, char *error)
4838{
4839 PJSON top = NULL;
4840 PGLOBAL g = (PGLOBAL)initid->ptr;
4841 PBSON bsp = (PBSON)g->Xchk;
4842
4843 if (bsp && !bsp->Changed) {
4844 // This constant function was recalled
4845 *res_length = sizeof(BSON);
4846 return (char*)bsp;
4847 } // endif bsp
4848
4849 if (!CheckMemory(g, initid, args, 1, false, false, true)) {
4850 int *x;
4851 uint n = 1;
4852 PJAR arp;
4853 PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
4854
4855 if (CheckPath(g, args, top, jvp, 1))
4856 PUSH_WARNING(g->Message);
4857 else if (jvp && jvp->GetValType() == TYPE_JAR) {
4858 if ((x = GetIntArgPtr(g, args, n))) {
4859 arp = jvp->GetArray();
4860 arp->DeleteValue(*x);
4861 arp->InitArray(GetMemPtr(g, args, 0));
4862 } else
4863 PUSH_WARNING("Missing or null array index");
4864
4865 } else {
4866 PUSH_WARNING("First argument target is not an array");
4867// if (g->Mrr) *error = 1;
4868 } // endif jvp
4869
4870 } // endif CheckMemory
4871
4872 // In case of error unchanged argument will be returned
4873 bsp = MakeBinResult(g, args, top, initid->max_length);
4874
4875 if (initid->const_item)
4876 // Keep result of constant function
4877 g->Xchk = bsp;
4878
4879 if (!bsp) {
4880 *is_null = 1;
4881 *error = 1;
4882 *res_length = 0;
4883 } else
4884 *res_length = sizeof(BSON);
4885
4886 return (char*)bsp;
4887} // end of jbin_array_delete
4888
4889void jbin_array_delete_deinit(UDF_INIT* initid)
4890{
4891 JsonFreeMem((PGLOBAL)initid->ptr);
4892} // end of jbin_array_delete_deinit
4893
4894/*********************************************************************************/
4895/* Make a Json Object containing all the parameters. */
4896/*********************************************************************************/
4897my_bool jbin_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4898{
4899 unsigned long reslen, memlen;
4900
4901 CalcLen(args, true, reslen, memlen);
4902 return JsonInit(initid, args, message, false, reslen, memlen);
4903} // end of jbin_object_init
4904
4905char *jbin_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
4906 unsigned long *res_length, char *is_null, char *error)
4907{
4908 PGLOBAL g = (PGLOBAL)initid->ptr;
4909 PBSON bsp = (PBSON)g->Xchk;
4910
4911 if (!bsp || bsp->Changed) {
4912 if (!CheckMemory(g, initid, args, args->arg_count, true)) {
4913 PJOB objp;
4914
4915 if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
4916 for (uint i = 0; i < args->arg_count; i++)
4917 objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
4918
4919
4920 if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
4921 strcat(bsp->Msg, " object");
4922
4923 } else
4924 bsp = NULL;
4925
4926 } else
4927 if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
4928 strncpy(bsp->Msg, g->Message, BMX);
4929
4930 // Keep result of constant function
4931 g->Xchk = (initid->const_item) ? bsp : NULL;
4932 } // endif bsp
4933
4934 if (!bsp) {
4935 *is_null = 1;
4936 *error = 1;
4937 *res_length = 0;
4938 } else
4939 *res_length = sizeof(BSON);
4940
4941 return (char*)bsp;
4942} // end of jbin_object
4943
4944void jbin_object_deinit(UDF_INIT* initid)
4945{
4946 JsonFreeMem((PGLOBAL)initid->ptr);
4947} // end of jbin_object_deinit
4948
4949/*********************************************************************************/
4950/* Make a Json Object containing all not null parameters. */
4951/*********************************************************************************/
4952my_bool jbin_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
4953{
4954 unsigned long reslen, memlen;
4955
4956 CalcLen(args, true, reslen, memlen);
4957 return JsonInit(initid, args, message, true, reslen, memlen);
4958} // end of jbin_object_nonull_init
4959
4960char *jbin_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
4961 unsigned long *res_length, char *is_null, char *error)
4962{
4963 PGLOBAL g = (PGLOBAL)initid->ptr;
4964 PBSON bsp = (PBSON)g->Xchk;
4965
4966 if (!bsp || bsp->Changed) {
4967 if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
4968 PJVAL jvp;
4969 PJOB objp;
4970
4971 if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
4972 for (uint i = 0; i < args->arg_count; i++)
4973 if (!(jvp = MakeValue(g, args, i))->IsNull())
4974 objp->SetValue(g, jvp, MakeKey(g, args, i));
4975
4976 if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
4977 strcat(bsp->Msg, " object");
4978
4979 } else
4980 bsp = NULL;
4981
4982 } else
4983 if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
4984 strncpy(bsp->Msg, g->Message, BMX);
4985
4986 // Keep result of constant function
4987 g->Xchk = (initid->const_item) ? bsp : NULL;
4988 } // endif bsp
4989
4990 if (!bsp) {
4991 *is_null = 1;
4992 *error = 1;
4993 *res_length = 0;
4994 } else
4995 *res_length = sizeof(BSON);
4996
4997 return (char*)bsp;
4998} // end of jbin_object_nonull
4999
5000void jbin_object_nonull_deinit(UDF_INIT* initid)
5001{
5002 JsonFreeMem((PGLOBAL)initid->ptr);
5003} // end of jbin_object_nonull_deinit
5004
5005/*********************************************************************************/
5006/* Make a Json Object containing all the key/value parameters. */
5007/*********************************************************************************/
5008my_bool jbin_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5009{
5010 unsigned long reslen, memlen;
5011
5012 if (args->arg_count % 2) {
5013 strcpy(message, "This function must have an even number of arguments");
5014 return true;
5015 } // endif arg_count
5016
5017 CalcLen(args, true, reslen, memlen);
5018 return JsonInit(initid, args, message, true, reslen, memlen);
5019} // end of jbin_object_key_init
5020
5021char *jbin_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
5022 unsigned long *res_length, char *is_null, char *error)
5023{
5024 PGLOBAL g = (PGLOBAL)initid->ptr;
5025 PBSON bsp = (PBSON)g->Xchk;
5026
5027 if (!bsp || bsp->Changed) {
5028 if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
5029 PJOB objp;
5030
5031 if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
5032 for (uint i = 0; i < args->arg_count; i += 2)
5033 objp->SetValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i));
5034
5035 if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
5036 strcat(bsp->Msg, " object");
5037
5038 } else
5039 bsp = NULL;
5040
5041 } else
5042 if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
5043 strncpy(bsp->Msg, g->Message, BMX);
5044
5045 // Keep result of constant function
5046 g->Xchk = (initid->const_item) ? bsp : NULL;
5047 } // endif bsp
5048
5049 if (!bsp) {
5050 *is_null = 1;
5051 *error = 1;
5052 *res_length = 0;
5053 } else
5054 *res_length = sizeof(BSON);
5055
5056 return (char*)bsp;
5057} // end of jbin_object_key
5058
5059void jbin_object_key_deinit(UDF_INIT* initid)
5060{
5061 JsonFreeMem((PGLOBAL)initid->ptr);
5062} // end of jbin_object_key_deinit
5063
5064/*********************************************************************************/
5065/* Add or replace a value in a Json Object. */
5066/*********************************************************************************/
5067my_bool jbin_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5068{
5069 unsigned long reslen, memlen;
5070
5071 if (args->arg_count < 2) {
5072 strcpy(message, "This function must have at least 2 arguments");
5073 return true;
5074 } else if (!IsJson(args, 0)) {
5075 strcpy(message, "First argument must be a json item");
5076 return true;
5077 } else
5078 CalcLen(args, true, reslen, memlen, true);
5079
5080 return JsonInit(initid, args, message, true, reslen, memlen);
5081 } // end of jbin_object_add_init
5082
5083char *jbin_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
5084 unsigned long *res_length, char *is_null, char *error)
5085{
5086 PJSON top = NULL;
5087 PGLOBAL g = (PGLOBAL)initid->ptr;
5088 PBSON bsp = (PBSON)g->Xchk;
5089
5090 if (bsp && !bsp->Changed) {
5091 // This constant function was recalled
5092 bsp = (PBSON)g->Xchk;
5093 *res_length = sizeof(BSON);
5094 return (char*)bsp;
5095 } // endif bsp
5096
5097 if (!CheckMemory(g, initid, args, 2, false, true, true)) {
5098 PCSZ key;
5099 PJOB jobp;
5100 PJVAL jvp = MakeValue(g, args, 0, &top);
5101 PJSON jsp = jvp->GetJson();
5102
5103 if (CheckPath(g, args, jsp, jvp, 2))
5104 PUSH_WARNING(g->Message);
5105 else if (jvp && jvp->GetValType() == TYPE_JOB) {
5106 PGLOBAL gb = GetMemPtr(g, args, 0);
5107
5108 jobp = jvp->GetObject();
5109 jvp = MakeValue(gb, args, 1);
5110 key = MakeKey(gb, args, 1);
5111 jobp->SetValue(gb, jvp, key);
5112 } else {
5113 PUSH_WARNING("First argument target is not an object");
5114// if (g->Mrr) *error = 1; (only if no path)
5115 } // endif jvp
5116
5117 } // endif CheckMemory
5118
5119 // In case of error unchanged argument will be returned
5120 bsp = MakeBinResult(g, args, top, initid->max_length);
5121
5122 if (initid->const_item)
5123 // Keep result of constant function
5124 g->Xchk = bsp;
5125
5126 if (!bsp) {
5127 *is_null = 1;
5128 *error = 1;
5129 *res_length = 0;
5130 } else
5131 *res_length = sizeof(BSON);
5132
5133 return (char*)bsp;
5134} // end of jbin_object_add
5135
5136void jbin_object_add_deinit(UDF_INIT* initid)
5137{
5138 JsonFreeMem((PGLOBAL)initid->ptr);
5139} // end of jbin_object_add_deinit
5140
5141/*********************************************************************************/
5142/* Delete a value from a Json object. */
5143/*********************************************************************************/
5144my_bool jbin_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5145{
5146 unsigned long reslen, memlen;
5147
5148 if (args->arg_count < 2) {
5149 strcpy(message, "This function must have 2 or 3 arguments");
5150 return true;
5151 } else if (!IsJson(args, 0)) {
5152 strcpy(message, "First argument must be a json item");
5153 return true;
5154 } else if (args->arg_type[1] != STRING_RESULT) {
5155 strcpy(message, "Second argument must be a key string");
5156 return true;
5157 } else
5158 CalcLen(args, true, reslen, memlen, true);
5159
5160 return JsonInit(initid, args, message, true, reslen, memlen);
5161 } // end of jbin_object_delete_init
5162
5163char *jbin_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
5164 unsigned long *res_length, char *is_null, char *error)
5165{
5166 PJSON top = NULL;
5167 PGLOBAL g = (PGLOBAL)initid->ptr;
5168 PBSON bsp = (PBSON)g->Xchk;
5169
5170 if (bsp && !bsp->Changed) {
5171 // This constant function was recalled
5172 bsp = (PBSON)g->Xchk;
5173 *res_length = sizeof(BSON);
5174 return (char*)bsp;
5175 } // endif bsp
5176
5177 if (!CheckMemory(g, initid, args, 1, false, true, true)) {
5178 PCSZ key;
5179 PJOB jobp;
5180 PJVAL jvp = MakeValue(g, args, 0, &top);
5181 PJSON jsp = jvp->GetJson();
5182
5183 if (CheckPath(g, args, top, jvp, 2))
5184 PUSH_WARNING(g->Message);
5185 else if (jvp && jvp->GetValType() == TYPE_JOB) {
5186 key = MakeKey(g, args, 1);
5187 jobp = jvp->GetObject();
5188 jobp->DeleteKey(key);
5189 } else {
5190 PUSH_WARNING("First argument target is not an object");
5191// if (g->Mrr) *error = 1; (only if no path)
5192 } // endif jvp
5193
5194 } // endif CheckMemory
5195
5196 // In case of error unchanged argument will be returned
5197 bsp = MakeBinResult(g, args, top, initid->max_length);
5198
5199 if (initid->const_item)
5200 // Keep result of constant function
5201 g->Xchk = bsp;
5202
5203 if (!bsp) {
5204 *is_null = 1;
5205 *error = 1;
5206 *res_length = 0;
5207 } else
5208 *res_length = sizeof(BSON);
5209
5210 return (char*)bsp;
5211} // end of jbin_object_delete
5212
5213void jbin_object_delete_deinit(UDF_INIT* initid)
5214{
5215 JsonFreeMem((PGLOBAL)initid->ptr);
5216} // end of jbin_object_delete_deinit
5217
5218/*********************************************************************************/
5219/* Returns an array of the Json object keys. */
5220/*********************************************************************************/
5221my_bool jbin_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5222{
5223 return json_object_list_init(initid, args, message);
5224} // end of jbin_object_list_init
5225
5226char *jbin_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
5227 unsigned long *res_length, char *is_null, char *error)
5228{
5229 PJAR jarp = NULL;
5230 PGLOBAL g = (PGLOBAL)initid->ptr;
5231 PBSON bsp = (PBSON)g->Xchk;
5232
5233 if (!bsp || bsp->Changed) {
5234 if (!CheckMemory(g, initid, args, 1, true, true)) {
5235 char *p;
5236 PJSON jsp;
5237 PJVAL jvp = MakeValue(g, args, 0);
5238
5239 if ((p = jvp->GetString(g))) {
5240 if (!(jsp = ParseJson(g, p, strlen(p)))) {
5241 PUSH_WARNING(g->Message);
5242 return NULL;
5243 } // endif jsp
5244
5245 } else
5246 jsp = jvp->GetJson();
5247
5248 if (jsp->GetType() == TYPE_JOB) {
5249 jarp = ((PJOB)jsp)->GetKeyList(g);
5250 } else {
5251 PUSH_WARNING("First argument is not an object");
5252 if (g->Mrr) *error = 1;
5253 } // endif jsp type
5254
5255 } // endif CheckMemory
5256
5257 if ((bsp = JbinAlloc(g, args, initid->max_length, jarp)))
5258 strcat(bsp->Msg, " array");
5259
5260 // Keep result of constant function
5261 g->Xchk = (initid->const_item) ? bsp : NULL;
5262 } // endif bsp
5263
5264 if (!bsp) {
5265 *is_null = 1;
5266 *error = 1;
5267 *res_length = 0;
5268 } else
5269 *res_length = sizeof(BSON);
5270
5271 return (char*)bsp;
5272} // end of jbin_object_list
5273
5274void jbin_object_list_deinit(UDF_INIT* initid)
5275{
5276 JsonFreeMem((PGLOBAL)initid->ptr);
5277} // end of jbin_object_list_deinit
5278
5279/*********************************************************************************/
5280/* Get a Json item from a Json document. */
5281/*********************************************************************************/
5282my_bool jbin_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5283{
5284 return json_get_item_init(initid, args, message);
5285} // end of jbin_get_item_init
5286
5287char *jbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
5288 unsigned long *res_length, char *is_null, char *error)
5289{
5290 char *path;
5291 PJSON jsp;
5292 PJSNX jsx;
5293 PJVAL jvp;
5294 PBSON bsp = NULL;
5295 PGLOBAL g = (PGLOBAL)initid->ptr;
5296
5297 if (g->N) {
5298 bsp = (PBSON)g->Activityp;
5299 goto fin;
5300 } else if (initid->const_item)
5301 g->N = 1;
5302
5303 if (!g->Xchk) {
5304 if (CheckMemory(g, initid, args, 1, true, true)) {
5305 PUSH_WARNING("CheckMemory error");
5306 goto fin;
5307 } // endif CheckMemory
5308
5309 jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
5310 jsp = jvp->GetJson();
5311
5312 if (g->Mrr) { // First argument is a constant
5313 g->Xchk = jsp;
5314 JsonMemSave(g);
5315 } // endif Mrr
5316
5317 } else
5318 jsp = (PJSON)g->Xchk;
5319
5320 path = MakePSZ(g, args, 1);
5321 jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
5322
5323 if (!jsx || jsx->SetJpath(g, path, false)) {
5324 PUSH_WARNING(g->Message);
5325 goto fin;
5326 } // endif SetJpath
5327
5328 // Get the json tree
5329 if ((jvp = jsx->GetRowValue(g, jsp, 0, false))) {
5330 jsp = (jvp->GetJsp()) ? jvp->GetJsp() : JvalNew(g, TYPE_VAL, jvp->GetValue());
5331
5332 if ((bsp = JbinAlloc(g, args, initid->max_length, jsp)))
5333 strcat(bsp->Msg, " item");
5334 else
5335 *error = 1;
5336
5337 } // endif jvp
5338
5339 if (initid->const_item)
5340 // Keep result of constant function
5341 g->Activityp = (PACTIVITY)bsp;
5342
5343 fin:
5344 if (!bsp) {
5345 *is_null = 1;
5346 *res_length = 0;
5347 } else
5348 *res_length = sizeof(BSON);
5349
5350 return (char*)bsp;
5351} // end of jbin_get_item
5352
5353void jbin_get_item_deinit(UDF_INIT* initid)
5354{
5355 JsonFreeMem((PGLOBAL)initid->ptr);
5356} // end of jbin_get_item_deinit
5357
5358/*********************************************************************************/
5359/* Merge two arrays or objects. */
5360/*********************************************************************************/
5361my_bool jbin_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5362{
5363 unsigned long reslen, memlen;
5364
5365 if (args->arg_count < 2) {
5366 strcpy(message, "This function must have at least 2 arguments");
5367 return true;
5368 } else if (!IsJson(args, 0)) {
5369 strcpy(message, "First argument must be a json item");
5370 return true;
5371 } else if (!IsJson(args, 1)) {
5372 strcpy(message, "Second argument must be a json item");
5373 return true;
5374 } else
5375 CalcLen(args, false, reslen, memlen, true);
5376
5377 return JsonInit(initid, args, message, true, reslen, memlen);
5378 } // end of jbin_item_merge_init
5379
5380char *jbin_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
5381 unsigned long *res_length, char *is_null, char *error)
5382{
5383 PJSON top = NULL;
5384 PGLOBAL g = (PGLOBAL)initid->ptr;
5385 PBSON bsp = (PBSON)g->Xchk;
5386
5387 if (bsp && !bsp->Changed) {
5388 // This constant function was recalled
5389 *res_length = sizeof(BSON);
5390 return (char*)bsp;
5391 } // endif bsp
5392
5393 if (!CheckMemory(g, initid, args, 2, false, false, true)) {
5394 PJVAL jvp;
5395 PJSON jsp[2] = {NULL, NULL};
5396 PGLOBAL gb = GetMemPtr(g, args, 0);
5397
5398 for (int i = 0; i < 2; i++) {
5399 jvp = MakeValue(g, args, i);
5400 if (!i) top = jvp->GetJson();
5401
5402 if (jvp->GetValType() != TYPE_JAR && jvp->GetValType() != TYPE_JOB) {
5403 sprintf(g->Message, "Argument %d is not an array or object", i);
5404 PUSH_WARNING(g->Message);
5405 } else
5406 jsp[i] = jvp->GetJsp();
5407
5408 } // endfor i
5409
5410 if (jsp[0] && jsp[0]->Merge(gb, jsp[1]))
5411 PUSH_WARNING(gb->Message);
5412
5413 } // endif CheckMemory
5414
5415 // In case of error unchanged first argument will be returned
5416 bsp = MakeBinResult(g, args, top, initid->max_length);
5417
5418 if (initid->const_item)
5419 // Keep result of constant function
5420 g->Xchk = bsp;
5421
5422 if (!bsp) {
5423 *is_null = 1;
5424 *error = 1;
5425 *res_length = 0;
5426 } else
5427 *res_length = sizeof(BSON);
5428
5429 return (char*)bsp;
5430} // end of jbin_item_merge
5431
5432void jbin_item_merge_deinit(UDF_INIT* initid)
5433{
5434 JsonFreeMem((PGLOBAL)initid->ptr);
5435} // end of jbin_item_merge_deinit
5436
5437/*********************************************************************************/
5438/* This function is used by the jbin_set/insert/update functions. */
5439/*********************************************************************************/
5440char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
5441 unsigned long *res_length, char *is_null, char *error)
5442{
5443 char *p, *path;
5444 int w;
5445 my_bool b = true;
5446 PJSON jsp;
5447 PJSNX jsx;
5448 PJVAL jvp = NULL;
5449 PBSON bsp = NULL;
5450 PGLOBAL g = (PGLOBAL)initid->ptr;
5451 PGLOBAL gb = GetMemPtr(g, args, 0);
5452
5453 if (g->N) {
5454 bsp = (PBSON)g->Activityp;
5455 goto fin;
5456 } else if (initid->const_item)
5457 g->N = 1;
5458
5459 if (!strcmp(result, "$set"))
5460 w = 0;
5461 else if (!strcmp(result, "$insert"))
5462 w = 1;
5463 else if (!strcmp(result, "$update"))
5464 w = 2;
5465 else {
5466 PUSH_WARNING("Logical error, please contact CONNECT developer");
5467 goto fin;
5468 } // endelse
5469
5470 if (!g->Xchk) {
5471 if (CheckMemory(g, initid, args, 1, true, false, true)) {
5472 PUSH_WARNING("CheckMemory error");
5473 goto fin;
5474 } else
5475 jvp = MakeValue(g, args, 0);
5476
5477 if ((p = jvp->GetString(g))) {
5478 if (!(jsp = ParseJson(g, p, strlen(p)))) {
5479 PUSH_WARNING(g->Message);
5480 goto fin;
5481 } // endif jsp
5482
5483 } else
5484 jsp = jvp->GetJson();
5485
5486 if (g->Mrr) { // First argument is a constant
5487 g->Xchk = jsp;
5488 JsonMemSave(g);
5489 } // endif Mrr
5490
5491 } else
5492 jsp = (PJSON)g->Xchk;
5493
5494 jsx = new(g)JSNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
5495
5496 for (uint i = 1; i+1 < args->arg_count; i += 2) {
5497 jvp = MakeValue(gb, args, i);
5498 path = MakePSZ(g, args, i+1);
5499
5500 if (jsx->SetJpath(g, path, false)) {
5501 PUSH_WARNING(g->Message);
5502 continue;
5503 } // endif SetJpath
5504
5505 if (w) {
5506 jsx->ReadValue(g);
5507 b = jsx->GetValue()->IsNull();
5508 b = (w == 1) ? b : !b;
5509 } // endif w
5510
5511 if (b && jsx->WriteValue(gb, jvp))
5512 PUSH_WARNING(g->Message);
5513
5514 } // endfor i
5515
5516 if (!(bsp = MakeBinResult(g, args, jsp, initid->max_length, INT_MAX32)))
5517 *error = 1;
5518
5519 if (initid->const_item)
5520 // Keep result of constant function
5521 g->Activityp = (PACTIVITY)bsp;
5522
5523fin:
5524 if (!bsp) {
5525 *is_null = 1;
5526 *res_length = 0;
5527 } else
5528 *res_length = sizeof(BSON);
5529
5530 return (char*)bsp;
5531} // end of bin_handle_item
5532
5533/*********************************************************************************/
5534/* Set Json items of a Json document according to path. */
5535/*********************************************************************************/
5536my_bool jbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5537{
5538 unsigned long reslen, memlen, more = 0;
5539 int n = IsJson(args, 0);
5540
5541 if (!(args->arg_count % 2)) {
5542 strcpy(message, "This function must have an odd number of arguments");
5543 return true;
5544 } else if (!n && args->arg_type[0] != STRING_RESULT) {
5545 strcpy(message, "First argument must be a json item");
5546 return true;
5547 } else
5548 CalcLen(args, false, reslen, memlen);
5549
5550 if (n == 2 && args->args[0]) {
5551 char fn[_MAX_PATH];
5552 long fl;
5553
5554 memcpy(fn, args->args[0], args->lengths[0]);
5555 fn[args->lengths[0]] = 0;
5556 fl = GetFileLength(fn);
5557 more = fl * 3;
5558 } else if (n != 3)
5559 more = args->lengths[0] * 3;
5560
5561 return JsonInit(initid, args, message, true, reslen, memlen, more);
5562 } // end of jbin_set_item_init
5563
5564char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
5565 unsigned long *res_length, char *is_null, char *p)
5566{
5567 strcpy(result, "$set");
5568 return bin_handle_item(initid, args, result, res_length, is_null, p);
5569} // end of jbin_set_item
5570
5571void jbin_set_item_deinit(UDF_INIT* initid)
5572{
5573 JsonFreeMem((PGLOBAL)initid->ptr);
5574} // end of jbin_set_item_deinit
5575
5576/*********************************************************************************/
5577/* Insert Json items of a Json document according to path. */
5578/*********************************************************************************/
5579my_bool jbin_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5580{
5581 return json_set_item_init(initid, args, message);
5582} // end of jbin_insert_item_init
5583
5584char *jbin_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
5585 unsigned long *res_length, char *is_null, char *p)
5586{
5587 strcpy(result, "$insert");
5588 return bin_handle_item(initid, args, result, res_length, is_null, p);
5589} // end of jbin_insert_item
5590
5591void jbin_insert_item_deinit(UDF_INIT* initid)
5592{
5593 JsonFreeMem((PGLOBAL)initid->ptr);
5594} // end of jbin_insert_item_deinit
5595
5596/*********************************************************************************/
5597/* Update Json items of a Json document according to path. */
5598/*********************************************************************************/
5599my_bool jbin_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5600{
5601 return json_set_item_init(initid, args, message);
5602} // end of jbin_update_item_init
5603
5604char *jbin_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
5605 unsigned long *res_length, char *is_null, char *p)
5606{
5607 strcpy(result, "$update");
5608 return bin_handle_item(initid, args, result, res_length, is_null, p);
5609} // end of jbin_update_item
5610
5611void jbin_update_item_deinit(UDF_INIT* initid)
5612{
5613 JsonFreeMem((PGLOBAL)initid->ptr);
5614} // end of jbin_update_item_deinit
5615
5616/*********************************************************************************/
5617/* Returns a json file as a json item. */
5618/*********************************************************************************/
5619my_bool jbin_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5620{
5621 unsigned long reslen, memlen, fl, more = 1024;
5622
5623 if (args->arg_count < 1 || args->arg_count > 4) {
5624 strcpy(message, "This function only accepts 1 to 4 arguments");
5625 return true;
5626 } else if (args->arg_type[0] != STRING_RESULT || !args->args[0]) {
5627 strcpy(message, "First argument must be a constant string (file name)");
5628 return true;
5629 } else if (args->arg_count > 1 && args->arg_type[1] != STRING_RESULT) {
5630 strcpy(message, "Second argument is not a string (path)");
5631 return true;
5632 } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
5633 strcpy(message, "Third argument is not an integer (pretty)");
5634 return true;
5635 } else if (args->arg_count > 3) {
5636 if (args->arg_type[3] != INT_RESULT) {
5637 strcpy(message, "Fourth argument is not an integer (memory)");
5638 return true;
5639 } else
5640 more += (ulong)*(longlong*)args->args[3];
5641
5642 } // endifs
5643
5644 initid->maybe_null = 1;
5645 CalcLen(args, false, reslen, memlen);
5646 fl = GetFileLength(args->args[0]);
5647 reslen += fl;
5648 more += fl * M;
5649//memlen += more;
5650 return JsonInit(initid, args, message, true, reslen, memlen, more);
5651} // end of jbin_file_init
5652
5653char *jbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
5654 unsigned long *res_length, char *is_null, char *error)
5655{
5656 char *fn;
5657 int pretty, len = 0, pty = 3;
5658 PJSON jsp;
5659 PJVAL jvp = NULL;
5660 PGLOBAL g = (PGLOBAL)initid->ptr;
5661 PBSON bsp = (PBSON)g->Xchk;
5662
5663 if (bsp && !bsp->Changed)
5664 goto fin;
5665
5666 PlugSubSet(g, g->Sarea, g->Sarea_Size);
5667 g->Xchk = NULL;
5668 fn = MakePSZ(g, args, 0);
5669 pretty = (args->arg_count > 2 && args->args[2]) ? (int)*(longlong*)args->args[2] : 3;
5670
5671 /*********************************************************************************/
5672 /* Parse the json file and allocate its tree structure. */
5673 /*********************************************************************************/
5674 if (!(jsp = ParseJsonFile(g, fn, &pty, len))) {
5675 PUSH_WARNING(g->Message);
5676 *error = 1;
5677 goto fin;
5678 } // endif jsp
5679
5680 if (pty == 3)
5681 PUSH_WARNING("File pretty format cannot be determined");
5682 else if (pretty != 3 && pty != pretty)
5683 PUSH_WARNING("File pretty format doesn't match the specified pretty value");
5684 else if (pretty == 3)
5685 pretty = pty;
5686
5687 if ((bsp = JbinAlloc(g, args, len, jsp))) {
5688 strcat(bsp->Msg, " file");
5689 bsp->Filename = fn;
5690 bsp->Pretty = pretty;
5691 } else {
5692 *error = 1;
5693 goto fin;
5694 } // endif bsp
5695
5696 // Check whether a path was specified
5697 if (CheckPath(g, args, jsp, jvp, 1)) {
5698 PUSH_WARNING(g->Message);
5699 bsp = NULL;
5700 goto fin;
5701 } else if (jvp)
5702 bsp->Jsp = jvp->GetJsp();
5703
5704 if (initid->const_item)
5705 // Keep result of constant function
5706 g->Xchk = bsp;
5707
5708 fin:
5709 if (!bsp) {
5710 *res_length = 0;
5711 *is_null = 1;
5712 } else
5713 *res_length = sizeof(BSON);
5714
5715 return (char*)bsp;
5716} // end of jbin_file
5717
5718void jbin_file_deinit(UDF_INIT* initid)
5719{
5720 JsonFreeMem((PGLOBAL)initid->ptr);
5721} // end of jbin_file_deinit
5722
5723/*********************************************************************************/
5724/* Serialize a Json document. . */
5725/*********************************************************************************/
5726my_bool json_serialize_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5727{
5728 unsigned long reslen, memlen;
5729
5730 if (args->arg_count != 1) {
5731 strcpy(message, "This function must have 1 argument");
5732 return true;
5733 } else if (args->args[0] && IsJson(args, 0) != 3) {
5734 strcpy(message, "Argument must be a Jbin tree");
5735 return true;
5736 } else
5737 CalcLen(args, false, reslen, memlen);
5738
5739 return JsonInit(initid, args, message, false, reslen, memlen);
5740} // end of json_serialize_init
5741
5742char *json_serialize(UDF_INIT *initid, UDF_ARGS *args, char *result,
5743 unsigned long *res_length, char *, char *error)
5744{
5745 char *str;
5746 PGLOBAL g = (PGLOBAL)initid->ptr;
5747
5748 if (!g->Xchk) {
5749 if (IsJson(args, 0) == 3) {
5750 PBSON bsp = (PBSON)args->args[0];
5751
5752 JsonSubSet(g);
5753
5754 if (!(str = Serialize(g, bsp->Jsp, NULL, 0)))
5755 str = strcpy(result, g->Message);
5756
5757 // Keep result of constant function
5758 g->Xchk = (initid->const_item) ? str : NULL;
5759 } else {
5760 *error = 1;
5761 str = strcpy(result, "Argument is not a Jbin tree");
5762 } // endif
5763
5764 } else
5765 str = (char*)g->Xchk;
5766
5767 *res_length = strlen(str);
5768 return str;
5769} // end of json_serialize
5770
5771void json_serialize_deinit(UDF_INIT* initid)
5772{
5773 JsonFreeMem((PGLOBAL)initid->ptr);
5774} // end of json_serialize_deinit
5775
5776/*********************************************************************************/
5777/* Utility function returning an environment variable value. */
5778/*********************************************************************************/
5779my_bool envar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5780{
5781 if (args->arg_count != 1) {
5782 strcpy(message, "Unique argument must be an environment variable name");
5783 return true;
5784 } else {
5785 initid->maybe_null = true;
5786 return false;
5787 } // endif count
5788
5789} // end of envar_init
5790
5791char *envar(UDF_INIT *initid, UDF_ARGS *args, char *result,
5792 unsigned long *res_length, char *is_null, char *)
5793{
5794 char *str, name[256];
5795 int n = MY_MIN(args->lengths[0], sizeof(name) - 1);
5796
5797 memcpy(name, args->args[0], n);
5798 name[n] = 0;
5799
5800 if (!(str = getenv(name))) {
5801 *res_length = 0;
5802 *is_null = 1;
5803 } else
5804 *res_length = strlen(str);
5805
5806 return str;
5807} // end of envar
5808
5809/*********************************************************************************/
5810/* Returns the distinct number of B occurences in A. */
5811/*********************************************************************************/
5812my_bool countin_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
5813{
5814 if (args->arg_count != 2) {
5815 strcpy(message, "This function must have 2 arguments");
5816 return true;
5817 } else if (args->arg_type[0] != STRING_RESULT) {
5818 strcpy(message, "First argument must be string");
5819 return true;
5820 } else if (args->arg_type[1] != STRING_RESULT) {
5821 strcpy(message, "Second argument is not a string");
5822 return true;
5823 } // endif args
5824
5825 return false;
5826} // end of countin_init
5827
5828long long countin(UDF_INIT *initid, UDF_ARGS *args, char *result,
5829 unsigned long *res_length, char *is_null, char *)
5830{
5831 PSZ str1, str2;
5832 char *s;
5833 long long n = 0;
5834 size_t lg;
5835
5836 lg = (size_t)args->lengths[0];
5837 s = str1 = (PSZ)malloc(lg + 1);
5838 memcpy(str1, args->args[0], lg);
5839 str1[lg] = 0;
5840
5841 lg = (size_t)args->lengths[1];
5842 str2 = (PSZ)malloc(lg + 1);
5843 memcpy(str2, args->args[1], lg);
5844 str2[lg] = 0;
5845
5846 while (s = strstr(s, str2)) {
5847 n++;
5848 s += lg;
5849 } // endwhile
5850
5851 free(str1);
5852 free(str2);
5853 return n;
5854} // end of countin
5855