/************* tabjson C++ Program Source Code File (.CPP) *************/ /* PROGRAM NAME: tabjson Version 1.9 */ /* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */ /* This program are the JSON class DB execution routines. */ /***********************************************************************/ #undef BSON_SUPPORT
/***********************************************************************/ /* Include relevant sections of the MariaDB header file. */ /***********************************************************************/ #include <my_global.h> #include <mysqld.h> #include <sql_error.h>
/***********************************************************************/ /* Include application header files: */ /* global.h is header containing all global declarations. */ /* plgdbsem.h is header containing the DB application declarations. */ /* tdbdos.h is header containing the TDBDOS declarations. */ /* json.h is header containing the JSON classes declarations. */ /***********************************************************************/ #include"global.h" #include"plgdbsem.h" //#include "xtable.h" #include"maputil.h" #include"filamtxt.h" #include"tabdos.h" //#include "resource.h" // for IDS_COLUMNS #include"tabjson.h" #include"filamap.h" #ifdefined(GZ_SUPPORT) #include"filamgz.h" #endif// GZ_SUPPORT #ifdefined(ZIP_SUPPORT) #include"filamzip.h" #endif// ZIP_SUPPORT #ifdefined(JAVA_SUPPORT) #include"jmgfam.h" #endif// JAVA_SUPPORT #ifdefined(CMGO_SUPPORT) #include"cmgfam.h" #endif// CMGO_SUPPORT #include"tabmul.h" #include"checklvl.h" #include"resource.h" #include"mycat.h"// for FNC_COL
/***********************************************************************/ /* This should be an option. */ /***********************************************************************/ #define MAXCOL 200/* Default max column nb in result */ //#define TYPE_UNKNOWN 12 /* Must be greater than other types */
if (!(n = pjdc->GetColumns(g, db, dsn, topt))) return NULL;
skipit: if (trace(1))
htrc("JSONColumns: n=%d len=%d\n", n, length[0]);
/*********************************************************************/ /* Allocate the structures used to refer to the result set. */ /*********************************************************************/
qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
buftyp, fldtyp, length, false, false);
/*********************************************************************/ /* Now get the results into blocks. */ /*********************************************************************/ for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) { if (jcp->Type == TYPE_UNKNOWN)
jcp->Type = TYPE_STRG; // Void column
crp = qrp->Colresp; // Column Name
crp->Kdata->SetValue(jcp->Name, i);
crp = crp->Next; // Data Type
crp->Kdata->SetValue(jcp->Type, i);
crp = crp->Next; // Type Name
crp->Kdata->SetValue(GetTypeName(jcp->Type), i);
crp = crp->Next; // Precision
crp->Kdata->SetValue(jcp->Len, i);
crp = crp->Next; // Length
crp->Kdata->SetValue(jcp->Len, i);
crp = crp->Next; // Scale (precision)
crp->Kdata->SetValue(jcp->Scale, i);
crp = crp->Next; // Nullable
crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i);
crp = crp->Next; // Field format
if (crp->Kdata)
crp->Kdata->SetValue(jcp->Fmt, i);
} // endfor i
/*********************************************************************/ /* Return the result pointer. */ /*********************************************************************/ return qrp;
} // end of JSONColumns
/* -------------------------- Class JSONDISC ------------------------- */
/***********************************************************************/ /* Class used to get the columns of a JSON table. */ /***********************************************************************/
JSONDISC::JSONDISC(PGLOBAL g, uint *lg)
{
length = lg;
jcp = fjcp = pjcp = NULL;
tdp = NULL;
tjnp = NULL;
jpp = NULL;
tjsp = NULL;
jsp = NULL;
row = NULL;
sep = NULL;
strfy = NULL;
i = n = bf = ncol = lvl = sz = limit = 0;
all = false;
} // end of JSONDISC constructor
if (tdp->Fn) { // We used the file name relative to recorded datapath
PlugSetPath(filename, tdp->Fn, tdp->GetPath());
tdp->Fn = PlugDup(g, filename);
} // endif Fn
return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff);
} // end of DefineAM
/***********************************************************************/ /* GetTable: makes a new Table Description Block. */ /***********************************************************************/
PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
{ if (trace(1))
htrc("JSON GetTable Pretty=%d Uri=%s\n", Pretty, SVP(Uri));
if (Catfunc == FNC_COL) returnnew(g)TDBJCL(this);
PTDBASE tdbp;
PTXF txfp = NULL;
// JSN not used for pretty=1 for insert or delete if (Pretty <= 0 || (Pretty == 1 && (m == MODE_READ || m == MODE_UPDATE))) {
USETEMP tmp = UseTemp(); bool map = Mapped && Pretty >= 0 && m != MODE_INSERT &&
!(tmp != TMP_NO && m == MODE_UPDATE) &&
!(tmp == TMP_FORCE &&
(m == MODE_UPDATE || m == MODE_DELETE));
return (colp->ParseJpath(g)) ? NULL : colp;
} // end of MakeCol
/***********************************************************************/ /* InsertSpecialColumn: Put a special column ahead of the column list.*/ /***********************************************************************/
PCOL TDBJSN::InsertSpecialColumn(PCOL colp)
{ if (!colp->IsSpecial()) return NULL;
//if (Xcol && ((SPCBLK*)colp)->GetRnm()) // colp->SetKey(0); // Rownum is no more a key
colp->SetNext(Columns);
Columns = colp; return colp;
} // end of InsertSpecialColumn
#if0 /***********************************************************************/ /* JSON Cardinality: returns table size in number of rows. */ /***********************************************************************/ int TDBJSN::Cardinality(PGLOBAL g)
{ if (!g) return0; elseif (Cardinal < 0) {
Cardinal = TDBDOS::Cardinality(g);
} // endif Cardinal
return Cardinal;
} // end of Cardinality
/***********************************************************************/ /* JSON GetMaxSize: returns file size estimate in number of lines. */ /***********************************************************************/ int TDBJSN::GetMaxSize(PGLOBAL g)
{ if (MaxSize < 0)
MaxSize = TDBDOS::GetMaxSize(g) * ((Xcol) ? Limit : 1);
return MaxSize;
} // end of GetMaxSize #endif// 0
/***********************************************************************/ /* JSON EstimatedLength. Returns an estimated minimum line length. */ /***********************************************************************/ int TDBJSN::EstimatedLength(void)
{ if (AvgLen <= 0) return (Lrecl ? Lrecl : 1024) / 8; // TODO: make it better else return AvgLen;
} // end of Estimated Length
/***********************************************************************/ /* Find the row in the tree structure. */ /***********************************************************************/
PJSON TDBJSN::FindRow(PGLOBAL g)
{ char *p, *objpath = PlugDup(g, Objname); char *sep = (char*)(Sep == ':' ? ":[" : ".["); bool bp = false, b = false;
PJSON jsp = Row;
PJVAL val = NULL;
for (; jsp && objpath; objpath = p, bp = b) { if ((p = strpbrk(objpath + 1, sep))) {
b = (*p == '[');
*p++ = 0;
} // endif p
if (!bp && *objpath != '[' && !IsNum(objpath)) { // objpass is a key
val = (jsp->GetType() == TYPE_JOB) ?
jsp->GetObject()->GetKeyValue(objpath) : NULL;
} else { if (bp || *objpath == '[') { if (objpath[strlen(objpath) - 1] != ']') {
snprintf(g->Message, sizeof(g->Message), "Invalid Table path %s", Objname); return NULL;
} elseif (!bp)
objpath++;
} // endif [
val = (jsp->GetType() == TYPE_JAR) ?
jsp->GetArray()->GetArrayValue(atoi(objpath) - B) : NULL;
} // endif objpath
if (Use == USE_OPEN) { /*******************************************************************/ /* Table already open, just replace it at its beginning. */ /*******************************************************************/ if (!To_Kindex) {
Txfp->Rewind(); // see comment in Work.log
} else// Table is to be accessed through a sorted index table
To_Kindex->Reset();
returnfalse;
} // endif use
/*********************************************************************/ /* Open according to logical input/output mode required. */ /* Use conventionnal input/output functions. */ /*********************************************************************/ if (Txfp->OpenTableFile(g)) returntrue;
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/ /* Lrecl is Ok. */ /*********************************************************************/
MODE mode = Mode;
// Buffer must be allocated in g->Sarea
Mode = MODE_ANY;
Txfp->AllocateBuffer(g);
Mode = mode;
/***********************************************************************/ /* SkipHeader: Physically skip first header line if applicable. */ /* This is called from TDBDOS::OpenDB and must be executed before */ /* Kindex construction if the file is accessed using an index. */ /***********************************************************************/ bool TDBJSN::SkipHeader(PGLOBAL g)
{ int len = GetFileLength(g); bool rc = false;
#ifdefined(_DEBUG) if (len < 0) returntrue; #endif// _DEBUG
if (Pretty == 1) { if (Mode == MODE_INSERT || Mode == MODE_DELETE) { // Mode Insert and delete are no more handled here
DBUG_ASSERT(false);
} elseif (len > 0) // !Insert && !Delete
rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g));
} // endif Pretty
return rc;
} // end of SkipHeader
/***********************************************************************/ /* ReadDB: Data Base read routine for JSN access method. */ /***********************************************************************/ int TDBJSN::ReadDB(PGLOBAL g) { int rc;
/***********************************************************************/ /* Make the top tree from the object path. */ /***********************************************************************/ bool TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp)
{ if (Objname) { if (!Val) { // Parse and allocate Objname item(s) char *p, *objpath = PlugDup(g, Objname); char *sep = (char*)(Sep == ':' ? ":[" : ".["); int i; bool bp = false, b = false;
PJOB objp;
PJAR arp;
PJVAL val = NULL;
Top = NULL;
for (; objpath; objpath = p, bp = b) { if ((p = strpbrk(objpath + 1, sep))) {
b = (*p == '[');
*p++ = 0;
} // endif p
/***********************************************************************/ /* WriteDB: Data Base write routine for JSON access method. */ /***********************************************************************/ int TDBJSN::WriteDB(PGLOBAL g)
{ int rc = TDBDOS::WriteDB(g);
PlugSubSet(G->Sarea, G->Sarea_Size);
Row->Clear(); return rc;
} // end of WriteDB
/***********************************************************************/ /* Data Base close routine for JSON access method. */ /***********************************************************************/ void TDBJSN::CloseDB(PGLOBAL g)
{
TDBDOS::CloseDB(g);
G = PlugExit(G);
} // end of CloseDB
// For calculated arrays, a local Value must be used switch (jnp->Op) { case OP_NUM:
jnp->Valp = AllocateValue(g, TYPE_INT); break; case OP_ADD: case OP_MULT: case OP_SEP: if (!IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision()); else
jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
break; case OP_MIN: case OP_MAX:
jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision()); break; case OP_CNC: if (IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision()); else
jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
break; default: break;
} // endswitch Op
if (jnp->Valp)
MulVal = AllocateValue(g, jnp->Valp);
returnfalse;
} // end of SetArrayOptions
/***********************************************************************/ /* Parse the eventual passed Jpath information. */ /* This information can be specified in the Fieldfmt column option */ /* when creating the table. It permits to indicate the position of */ /* the node corresponding to that column. */ /***********************************************************************/ bool JSONCOL::ParseJpath(PGLOBAL g)
{ char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL; int i; bool a;
if (To_Tdb->GetOrig()) { // This is an updated column, get nodes from origin for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp;
colp = (PJCOL)colp->GetNext()) if (!stricmp(Name, colp->GetName())) {
Nod = colp->Nod;
Nodes = colp->Nodes;
Xpd = colp->Xpd; goto fin;
} // endif Name
// Analyze the Jpath for this column for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
a = (p1 != NULL);
p1 = strchr(p, '[');
p2 = strchr(p, Sep);
if (!p2)
p2 = p1; elseif (p1) { if (p1 < p2)
p2 = p1; elseif (p1 == p2 + 1)
*p2++ = 0; // Old syntax .[ or :[ else
p1 = NULL;
} // endif p1
if (p2)
*p2++ = 0;
// Jpath must be explicit if (a || *p == 0 || *p == '[' || IsNum(p)) { // Analyse intermediate array processing if (SetArrayOptions(g, p, i, Nodes[i - 1].Key)) returntrue; elseif (Xpd && Tjp->Mode == MODE_DELETE) {
safe_strcpy(g->Message, sizeof(g->Message), "Cannot delete expanded columns"); returntrue;
} // endif Xpd
/***********************************************************************/ /* MakeJson: Serialize the json item and set value to it. */ /***********************************************************************/
PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp, int n)
{ if (Value->IsTypeNum()) {
safe_strcpy(g->Message, sizeof(g->Message), "Cannot make Json for a numeric column");
for (PJPR prp = ((PJOB)jsp)->GetFirst(); prp; prp = prp->Next)
jvp->SetKeyValue(g, GetRowValue(g, prp->Val, n + 1), prp->Key);
jsp = jvp;
} // endif Type
} // endif
Value->SetValue_psz(Serialize(g, jsp, NULL, 0)); return Value;
} // end of MakeJson
/***********************************************************************/ /* GetRowValue: */ /***********************************************************************/
PJVAL JSONCOL::GetRowValue(PGLOBAL g, PJSON row, int i)
{
PJVAL val = NULL;
for (; i < Nod && row; i++) { switch (row->GetType()) { case TYPE_JOB:
val = (Nodes[i].Key) ? ((PJOB)row)->GetKeyValue(Nodes[i].Key) : NULL; break; case TYPE_JAR:
val = ((PJAR)row)->GetArrayValue(Nodes[i].Rank); break; case TYPE_JVAL:
val = (PJVAL)row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->GetType());
val = NULL;
} // endswitch Type
if (i < Nod-1)
row = (val) ? val->GetJson() : NULL;
} // endfor i
return val;
} // end of GetRowValue
/***********************************************************************/ /* SetValue: Set a value from a JVALUE contains. */ /***********************************************************************/ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL jvp)
{ if (jvp) {
vp->SetNull(false);
switch (jvp->GetValType()) { case TYPE_STRG: case TYPE_INTG: case TYPE_BINT: case TYPE_DBL: case TYPE_DTM: switch (vp->GetType()) { case TYPE_STRING:
vp->SetValue_psz(jvp->GetString(g)); break; case TYPE_INT: case TYPE_SHORT: case TYPE_TINY:
vp->SetValue(jvp->GetInteger()); break; case TYPE_BIGINT:
vp->SetValue(jvp->GetBigint()); break; case TYPE_DOUBLE:
vp->SetValue(jvp->GetFloat());
if (jvp->GetValType() == TYPE_DBL)
vp->SetPrec(jvp->Nd);
break; case TYPE_DATE: if (jvp->GetValType() == TYPE_STRG) {
PSZ dat = jvp->GetString(g);
if (!IsNum(dat)) { if (!((DTVAL*)vp)->IsFormatted())
((DTVAL*)vp)->SetFormat(g, "YYYY-MM-DDThh:mm:ssZ", 20, 0);
// Set null when applicable if (!Nullable)
Value->SetNull(false);
} // end of ReadColumn
/***********************************************************************/ /* GetColumnValue: */ /***********************************************************************/
PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
{
PJAR arp;
PJVAL val = NULL;
for (; i < Nod && row; i++) { if (Nodes[i].Op == OP_NUM) {
Value->SetValue(row->GetType() == TYPE_JAR ? ((PJAR)row)->size() : 1); return(Value);
} elseif (Nodes[i].Op == OP_XX) { return MakeJson(G, row, i);
} elseswitch (row->GetType()) { case TYPE_JOB: if (!Nodes[i].Key) { // Expected Array was not there, wrap the value if (i < Nod-1) continue; else
val = new(G) JVALUE(row);
} else
val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
break; case TYPE_JAR:
arp = (PJAR)row;
if (!Nodes[i].Key) { if (Nodes[i].Op == OP_EQ)
val = arp->GetArrayValue(Nodes[i].Rank); elseif (Nodes[i].Op == OP_EXP) return ExpandArray(g, arp, i); else return CalculateArray(g, arp, i);
} else { // Unexpected array, unwrap it as [0]
val = arp->GetArrayValue(0);
i--;
} // endif's
break; case TYPE_JVAL:
val = (PJVAL)row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->GetType());
val = NULL;
} // endswitch Type
if (i < Nod-1)
row = (val) ? val->GetJson() : NULL;
} // endfor i
SetJsonValue(g, Value, val); return Value;
} // end of GetColumnValue
/***********************************************************************/ /* ExpandArray: */ /***********************************************************************/
PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
{ int ars = MY_MIN(Tjp->Limit, arp->size());
PJVAL jvp;
JVALUE jval;
if (!ars) {
Value->Reset();
Value->SetNull(true);
Tjp->NextSame = 0; return Value;
} // endif ars
if (op == OP_SEP) { // Calculate average
MulVal->SetValue(nv);
val[0] = vp;
val[1] = MulVal;
if (vp->Compute(g, val, 2, OP_DIV))
vp->Reset();
} // endif Op
Tjp->NextSame = nextsame; return vp;
} // end of CalculateArray
/***********************************************************************/ /* GetRow: Get the object containing this column. */ /***********************************************************************/
PJSON JSONCOL::GetRow(PGLOBAL g)
{
PJVAL val = NULL;
PJAR arp;
PJSON nwr, row = Tjp->Row;
for (int i = 0; i < Nod && row; i++) { if (i < Nod-1 && Nodes[i+1].Op == OP_XX) break; elseswitch (row->GetType()) { case TYPE_JOB: if (!Nodes[i].Key) // Expected Array was not there, wrap the value continue;
val = ((PJOB)row)->GetKeyValue(Nodes[i].Key); break; case TYPE_JAR:
arp = (PJAR)row;
if (!Nodes[i].Key) { if (Nodes[i].Op == OP_EQ)
val = arp->GetArrayValue(Nodes[i].Rank); else
val = arp->GetArrayValue(Nodes[i].Rx);
} else { // Unexpected array, unwrap it as [0]
val = arp->GetArrayValue(0);
i--;
} // endif Nodes
break; case TYPE_JVAL:
val = (PJVAL)row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->GetType());
val = NULL;
} // endswitch Type
if (row->GetType() == TYPE_JOB) {
((PJOB)row)->SetKeyValue(G, new(G) JVALUE(nwr), Nodes[i-1].Key);
} elseif (row->GetType() == TYPE_JAR) {
((PJAR)row)->AddArrayValue(G, new(G) JVALUE(nwr));
((PJAR)row)->InitArray(G);
} else {
safe_strcpy(g->Message, sizeof(g->Message), "Wrong type when writing new row");
nwr = NULL;
} // endif's
row = nwr;
} // endfor i
break;
} // endelse
} // endfor i
return row;
} // end of GetRow
/***********************************************************************/ /* WriteColumn: */ /***********************************************************************/ void JSONCOL::WriteColumn(PGLOBAL g)
{ if (Xpd && Tjp->Pretty < 2) {
safe_strcpy(g->Message, sizeof(g->Message), "Cannot write expanded column when Pretty is not 2"); throw666;
} // endif Xpd
/*********************************************************************/ /* Check whether this node must be written. */ /*********************************************************************/ if (Value != To_Val)
Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
/*********************************************************************/ /* On INSERT Null values are represented by no node. */ /*********************************************************************/ if (Value->IsNull() && Tjp->Mode == MODE_INSERT) return;
// fall through case TYPE_DATE: case TYPE_INT: case TYPE_TINY: case TYPE_SHORT: case TYPE_BIGINT: case TYPE_DOUBLE: if (arp) { if (Nodes[Nod-1].Op == OP_EQ)
arp->SetArrayValue(G, new(G) JVALUE(G, Value), Nodes[Nod-1].Rank); else
arp->AddArrayValue(G, new(G) JVALUE(G, Value));
// Used for update
PTDB TDBJSON::Clone(PTABS t)
{
PTDB tp;
PJCOL cp1, cp2;
PGLOBAL g = t->G;
tp = new(g) TDBJSON(this);
for (cp1 = (PJCOL)Columns; cp1; cp1 = (PJCOL)cp1->GetNext()) {
cp2 = new(g) JSONCOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of Clone
/***********************************************************************/ /* Make the document tree from the object path. */ /***********************************************************************/ int TDBJSON::MakeNewDoc(PGLOBAL g)
{ // Create a void table that will be populated
Doc = new(g) JARRAY;
if (MakeTopTree(g, Doc)) return RC_FX;
Done = true; return RC_OK;
} // end of MakeNewDoc
/***********************************************************************/ /* Make the document tree from a file. */ /***********************************************************************/ int TDBJSON::MakeDocument(PGLOBAL g)
{ char *p, *p1, *p2, *memory, *objpath, *key = NULL; int i = 0;
size_t len;
my_bool a;
MODE mode = Mode;
PJSON jsp;
PJOB objp = NULL;
PJAR arp = NULL;
PJVAL val = NULL;
if (Done) return RC_OK;
/*********************************************************************/ /* Create the mapping file object in mode read. */ /*********************************************************************/
Mode = MODE_READ;
if (!Txfp->OpenTableFile(g)) {
PFBLOCK fp = Txfp->GetTo_Fb();
if (!a && *p && *p != '[' && !IsNum(p)) { // obj is a key if (jsp->GetType() != TYPE_JOB) {
safe_strcpy(g->Message, sizeof(g->Message), "Table path does not match the json file"); return RC_FX;
} // endif Type
} else { if (*p == '[') { // Old style if (p[strlen(p) - 1] != ']') {
snprintf(g->Message, sizeof(g->Message), "Invalid Table path near %s", p); return RC_FX;
} else
p++;
} // endif p
if (jsp->GetType() != TYPE_JAR) {
safe_strcpy(g->Message, sizeof(g->Message), "Table path does not match the json file"); return RC_FX;
} // endif Type
arp = jsp->GetArray();
objp = NULL;
i = atoi(p) - B;
val = arp->GetArrayValue(i);
if (!val) {
snprintf(g->Message, sizeof(g->Message), "Cannot find array value %d", i); return RC_FX;
} // endif val
} // endif
jsp = val->GetJson();
} // endfor p
} // endif objpath
if (jsp && jsp->GetType() == TYPE_JAR)
Doc = jsp->GetArray(); else { // The table is void or is just one object or one value
Doc = new(g) JARRAY;
if (val) {
Doc->AddArrayValue(g, val);
Doc->InitArray(g);
} elseif (jsp) {
Doc->AddArrayValue(g, new(g) JVALUE(jsp));
Doc->InitArray(g);
} // endif val
if (objp)
objp->SetKeyValue(g, new(g) JVALUE(Doc), key); elseif (arp)
arp->SetArrayValue(g, new(g) JVALUE(Doc), i); else
Top = Doc;
} // endif jsp
Done = true; return RC_OK;
} // end of MakeDocument
/***********************************************************************/ /* JSON Cardinality: returns table size in number of rows. */ /***********************************************************************/ int TDBJSON::Cardinality(PGLOBAL g)
{ if (!g) return (Xcol || Multiple) ? 0 : 1; elseif (Cardinal < 0)
{ if (!Multiple) { if (MakeDocument(g) == RC_OK)
Cardinal = Doc->size();
} else return10;
} return Cardinal;
} // end of Cardinality
/***********************************************************************/ /* JSON GetMaxSize: returns table size estimate in number of rows. */ /***********************************************************************/ int TDBJSON::GetMaxSize(PGLOBAL g)
{ if (MaxSize < 0)
MaxSize = Cardinality(g) * ((Xcol) ? Limit : 1);
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/ /* ResetSize: call by TDBMUL when calculating size estimate. */ /***********************************************************************/ void TDBJSON::ResetSize(void)
{
MaxSize = Cardinal = -1;
Fpos = -1;
N = 0;
Done = false;
} // end of ResetSize
/***********************************************************************/ /* TDBJSON is not indexable. */ /***********************************************************************/ int TDBJSON::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool)
{ if (pxdf) {
safe_strcpy(g->Message, sizeof(g->Message), "JSON not indexable when pretty = 2"); return RC_FX;
} else return RC_OK;
} // end of MakeIndex
/***********************************************************************/ /* Return the position in the table. */ /***********************************************************************/ int TDBJSON::GetRecpos(void)
{ #if0 union {
uint Rpos;
BYTE Spos[4];
};
Rpos = htonl(Fpos);
Spos[0] = (BYTE)NextSame; return Rpos; #endif// 0 return Fpos;
} // end of GetRecpos
/***********************************************************************/ /* Set the position in the table. */ /***********************************************************************/ bool TDBJSON::SetRecpos(PGLOBAL, int recpos)
{ #if0 union {
uint Rpos;
BYTE Spos[4];
};
Fpos = recpos - 1; returnfalse;
} // end of SetRecpos
/***********************************************************************/ /* JSON Access Method opening routine. */ /***********************************************************************/ bool TDBJSON::OpenDB(PGLOBAL g)
{ if (Use == USE_OPEN) { /*******************************************************************/ /* Table already open replace it at its beginning. */ /*******************************************************************/
Fpos= -1;
NextSame = false;
SameRow = 0; returnfalse;
} // endif use
/*********************************************************************/ /* OpenDB: initialize the JSON file processing. */ /*********************************************************************/ if (MakeDocument(g) != RC_OK) returntrue;
if (Mode == MODE_INSERT) switch (Jmode) { case MODE_OBJECT: Row = new(g) JOBJECT; break; case MODE_ARRAY: Row = new(g) JARRAY; break; case MODE_VALUE: Row = new(g) JVALUE; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid Jmode %d", Jmode); returntrue;
} // endswitch Jmode
if (Xcol)
To_Filter = NULL; // Imcompatible
Use = USE_OPEN; returnfalse;
} // end of OpenDB
/***********************************************************************/ /* ReadDB: Data Base read routine for JSON access method. */ /***********************************************************************/ int TDBJSON::ReadDB(PGLOBAL)
{ int rc;
/***********************************************************************/ /* Data Base delete line routine for JSON access method. */ /***********************************************************************/ int TDBJSON::DeleteDB(PGLOBAL g, int irc)
{ if (irc == RC_OK) { // Deleted current row if (Doc->DeleteValue(Fpos)) {
snprintf(g->Message, sizeof(g->Message), "Value %d does not exist", Fpos + 1); return RC_FX;
} // endif Delete
Changed = true;
} elseif (irc == RC_FX) // Delete all for (int i = 0; i < Doc->size(); i++) {
Doc->DeleteValue(i);
Changed = true;
} // endfor i
return RC_OK;
} // end of DeleteDB
/***********************************************************************/ /* Data Base close routine for JSON access methods. */ /***********************************************************************/ void TDBJSON::CloseDB(PGLOBAL g)
{ if (!Changed) return;
// Save the modified document char filename[_MAX_PATH];
Doc->InitArray(g);
// We used the file name relative to recorded datapath
PlugSetPath(filename, ((PJDEF)To_Def)->Fn, GetPath());
// Serialize the modified table if (!Serialize(g, Top, filename, Pretty))
puts(g->Message);
} // end of CloseDB
/* ---------------------------TDBJCL class --------------------------- */
/***********************************************************************/ /* TDBJCL class constructor. */ /***********************************************************************/
TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp)
{
Topt = tdp->GetTopt();
Db = tdp->Schema;
Dsn = tdp->Uri;
} // end of TDBJCL constructor
/***********************************************************************/ /* GetResult: Get the list the JSON file columns. */ /***********************************************************************/
PQRYRES TDBJCL::GetResult(PGLOBAL g)
{ return JSONColumns(g, Db, Dsn, Topt, false);
} // end of GetResult
/* --------------------------- End of json --------------------------- */
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.40Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.