diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2021-07-24 16:28:57 +0200 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2021-07-24 16:28:57 +0200 |
commit | 0f18135ec8f90f5736829fb36cab3da9196fd09f (patch) | |
tree | 1bd1704bac088491e727b4edf397a4b0e3cbbfab | |
parent | 1c4b917f0e82081950ca256fd7698dab8f4722e6 (diff) | |
download | mariadb-git-0f18135ec8f90f5736829fb36cab3da9196fd09f.tar.gz |
- Make user variable prefix recognized by IsArgJson and IsJson
modified: storage/connect/bsonudf.cpp
modified: storage/connect/jsonudf.cpp
- Stringify option is now a ; separated list of columns
modified: storage/connect/json.cpp
modified: storage/connect/json.h
modified: storage/connect/mongo.h
modified: storage/connect/tabbson.cpp
modified: storage/connect/tabcmg.cpp
modified: storage/connect/tabcmg.h
modified: storage/connect/tabjmg.cpp
modified: storage/connect/tabjmg.h
modified: storage/connect/tabjson.cpp
- PrepareColist not a static function anymore (+ typo)
modified: storage/connect/taboccur.cpp
- JDVC: Recognize schema (database) from a wrapper server
modified: storage/connect/tabjdbc.cpp
-rw-r--r-- | storage/connect/bsonudf.cpp | 19 | ||||
-rw-r--r-- | storage/connect/json.cpp | 26 | ||||
-rw-r--r-- | storage/connect/json.h | 1 | ||||
-rw-r--r-- | storage/connect/jsonudf.cpp | 17 | ||||
-rw-r--r-- | storage/connect/mongo.h | 2 | ||||
-rw-r--r-- | storage/connect/tabbson.cpp | 5 | ||||
-rw-r--r-- | storage/connect/tabcmg.cpp | 3 | ||||
-rw-r--r-- | storage/connect/tabcmg.h | 2 | ||||
-rw-r--r-- | storage/connect/tabjdbc.cpp | 3 | ||||
-rw-r--r-- | storage/connect/tabjmg.cpp | 15 | ||||
-rw-r--r-- | storage/connect/tabjmg.h | 2 | ||||
-rw-r--r-- | storage/connect/tabjson.cpp | 5 | ||||
-rw-r--r-- | storage/connect/taboccur.cpp | 72 |
13 files changed, 111 insertions, 61 deletions
diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp index d3174580e7f..783be52602a 100644 --- a/storage/connect/bsonudf.cpp +++ b/storage/connect/bsonudf.cpp @@ -1889,24 +1889,31 @@ static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n) /*********************************************************************************/ int IsArgJson(UDF_ARGS *args, uint i) { - int n = 0; + char *pat = args->attributes[i]; + int n = 0; + + if (*pat == '@') { + pat++; + + if (*pat == '\'' || *pat == '"') + pat++; + + } // endif pat if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) { - } else if (!strnicmp(args->attributes[i], "Bson_", 5) || - !strnicmp(args->attributes[i], "Json_", 5)) { + } else if (!strnicmp(pat, "Bson_", 5) || !strnicmp(pat, "Json_", 5)) { if (!args->args[i] || strchr("[{ \t\r\n", *args->args[i])) n = 1; // arg should be is a json item // else // n = 2; // A file name may have been returned - } else if (!strnicmp(args->attributes[i], "Bbin_", 5)) { + } else if (!strnicmp(pat, "Bbin_", 5)) { if (args->lengths[i] == sizeof(BSON)) n = 3; // arg is a binary json item // else // n = 2; // A file name may have been returned - } else if (!strnicmp(args->attributes[i], "Bfile_", 6) || - !strnicmp(args->attributes[i], "Jfile_", 6)) { + } else if (!strnicmp(pat, "Bfile_", 6) || !strnicmp(pat, "Jfile_", 6)) { n = 2; // arg is a json file name #if 0 } else if (args->lengths[i]) { diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 9b7145bb498..b1d4decdcdb 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1,7 +1,7 @@ /*************** json CPP Declares Source Code File (.H) ***************/ -/* Name: json.cpp Version 1.5 */ +/* Name: json.cpp Version 1.6 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2014 - 2020 */ +/* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */ /* */ /* This file contains the JSON classes functions. */ /***********************************************************************/ @@ -55,6 +55,7 @@ char *GetExceptionDesc(PGLOBAL g, unsigned int e); char *GetJsonNull(void); int GetDefaultPrec(void); +int PrepareColist(char*); /***********************************************************************/ /* IsNum: check whether this string is all digits. */ @@ -111,6 +112,27 @@ char* NextChr(PSZ s, char sep) return p2; } // end of NextChr +/***********************************************************************/ +/* Stringified: check that this column is in the stringified list. */ +/***********************************************************************/ +bool Stringified(PCSZ strfy, char *colname) +{ + if (strfy) { + char *p, colist[512]; + int n; + + strncpy(colist, strfy, sizeof(colist) - 1); + n = PrepareColist(colist); + + for (p = colist; n && p; p += (strlen(p) + 1), n--) + if (!stricmp(p, colname)) + return true; + + } // endif strfy + + return false; +} // end of Stringified + #if 0 /***********************************************************************/ /* Allocate a VAL structure, make sure common field and Nd are zeroed. */ diff --git a/storage/connect/json.h b/storage/connect/json.h index 566cb64cc23..53fc5f65e7b 100644 --- a/storage/connect/json.h +++ b/storage/connect/json.h @@ -67,6 +67,7 @@ PJSON ParseJson(PGLOBAL g, char* s, size_t n, int* prty = NULL, bool* b = NULL); PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty); DllExport bool IsNum(PSZ s); bool IsArray(PSZ s); +bool Stringified(PCSZ strfy, char *colname); /***********************************************************************/ /* Class JDOC. The class for parsing and serializing json documents. */ diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index 1f635002e7e..c1df923f0b8 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -1524,22 +1524,31 @@ static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n) /*********************************************************************************/ int IsJson(UDF_ARGS *args, uint i, bool b) { - int n = 0; + char *pat = args->attributes[i]; + int n = 0; + + if (*pat == '@') { + pat++; + + if (*pat == '\'' || *pat == '"') + pat++; + + } // endif pat if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) { - } else if (!strnicmp(args->attributes[i], "Json_", 5)) { + } else if (!strnicmp(pat, "Json_", 5)) { if (!args->args[i] || strchr("[{ \t\r\n", *args->args[i])) n = 1; // arg should be is a json item else n = 2; // A file name may have been returned - } else if (!strnicmp(args->attributes[i], "Jbin_", 5)) { + } else if (!strnicmp(pat, "Jbin_", 5)) { if (args->lengths[i] == sizeof(BSON)) n = 3; // arg is a binary json item else n = 2; // A file name may have been returned - } else if (!strnicmp(args->attributes[i], "Jfile_", 6)) { + } else if (!strnicmp(pat, "Jfile_", 6)) { n = 2; // arg is a json file name } else if (b) { char *sap; diff --git a/storage/connect/mongo.h b/storage/connect/mongo.h index fddc491f2d0..7e92a7dc8e9 100644 --- a/storage/connect/mongo.h +++ b/storage/connect/mongo.h @@ -82,7 +82,7 @@ protected: PSZ Wrapname; /* Java wrapper name */ PCSZ Colist; /* Options list */ PCSZ Filter; /* Filtering query */ - PCSZ Strfy; /* Stringify column */ + PCSZ Strfy; /* The stringify columns */ int Base; /* The array index base */ int Version; /* The Java driver version */ bool Pipe; /* True is Colist is a pipeline */ diff --git a/storage/connect/tabbson.cpp b/storage/connect/tabbson.cpp index 7f5727a9713..3b1f1c84d1a 100644 --- a/storage/connect/tabbson.cpp +++ b/storage/connect/tabbson.cpp @@ -53,6 +53,7 @@ USETEMP UseTemp(void); bool JsonAllPath(void); int GetDefaultDepth(void); char *GetJsonNull(void); +bool Stringified(PCSZ, char*); /***********************************************************************/ /* BSONColumns: construct the result blocks containing the description */ @@ -436,7 +437,7 @@ bool BSONDISC::Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j) jcol.Type = TYPE_UNKNOWN; jcol.Len = jcol.Scale = 0; jcol.Cbn = true; - } else if (j < lvl && !(strfy && !stricmp(strfy, colname))) { + } else if (j < lvl && !Stringified(strfy, colname)) { if (!fmt[bf]) strcat(fmt, colname); @@ -507,7 +508,7 @@ bool BSONDISC::Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j) } // endswitch Type } else if (lvl >= 0) { - if (strfy && !stricmp(strfy, colname)) { + if (Stringified(strfy, colname)) { if (!fmt[bf]) strcat(fmt, colname); diff --git a/storage/connect/tabcmg.cpp b/storage/connect/tabcmg.cpp index 608445bb1ab..56d705f42ca 100644 --- a/storage/connect/tabcmg.cpp +++ b/storage/connect/tabcmg.cpp @@ -27,6 +27,7 @@ #include "filter.h" PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info); +bool Stringified(PCSZ, char*); /* -------------------------- Class CMGDISC -------------------------- */ @@ -397,7 +398,7 @@ MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) : EXTCOL(cdp, tdbp, cprec, i, "MGO") { Tmgp = (PTDBCMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); - Sgfy = (Tmgp->Strfy && !stricmp(Tmgp->Strfy, Name)); + Sgfy = Stringified(Tmgp->Strfy, Name); if ((Jpath = cdp->GetFmt())) { int n = strlen(Jpath) - 1; diff --git a/storage/connect/tabcmg.h b/storage/connect/tabcmg.h index 0a29a6ce909..9effe714fdd 100644 --- a/storage/connect/tabcmg.h +++ b/storage/connect/tabcmg.h @@ -75,7 +75,7 @@ protected: CMgoConn *Cmgp; // Points to a C Mongo connection class CMGOPARM Pcg; // Parms passed to Cmgp const Item *Cnd; // The first condition - PCSZ Strfy; // The stringified column + PCSZ Strfy; // The stringified columns int Fpos; // The current row index int N; // The current Rownum int B; // Array index base diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp index 7a8eedad12b..9721c62be7d 100644 --- a/storage/connect/tabjdbc.cpp +++ b/storage/connect/tabjdbc.cpp @@ -188,6 +188,9 @@ int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b) } else // host is a URL Url = PlugDup(g, server->host); + if (!Tabschema && server->db) + Tabschema = PlugDup(g, server->db); + if (!Username && server->username) Username = PlugDup(g, server->username); diff --git a/storage/connect/tabjmg.cpp b/storage/connect/tabjmg.cpp index 9271873b800..983ee39d65f 100644 --- a/storage/connect/tabjmg.cpp +++ b/storage/connect/tabjmg.cpp @@ -30,6 +30,7 @@ #define nullptr 0 PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info); +bool Stringified(PCSZ, char*); /* -------------------------- Class JMGDISC -------------------------- */ @@ -423,15 +424,19 @@ JMGCOL::JMGCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) : EXTCOL(cdp, tdbp, cprec, i, "MGO") { Tmgp = (PTDBJMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); - Sgfy = (Tmgp->Strfy && !stricmp(Tmgp->Strfy, Name)); + Sgfy = Stringified(Tmgp->Strfy, Name); if ((Jpath = cdp->GetFmt())) { - int n = strlen(Jpath) - 1; + int n = strlen(Jpath); - if (Jpath[n] == '*') { + if (n && Jpath[n - 1] == '*') { Jpath = PlugDup(g, cdp->GetFmt()); - if (Jpath[n - 1] == '.') n--; - Jpath[n] = 0; + + if (--n) { + if (Jpath[n - 1] == '.') n--; + Jpath[n] = 0; + } // endif n + Sgfy = true; } // endif Jpath diff --git a/storage/connect/tabjmg.h b/storage/connect/tabjmg.h index bc89319527a..cf7cff83b68 100644 --- a/storage/connect/tabjmg.h +++ b/storage/connect/tabjmg.h @@ -83,7 +83,7 @@ protected: PCSZ Coll_name; PCSZ Options; // The MongoDB options PCSZ Filter; // The filtering query - PCSZ Strfy; // The stringified column + PCSZ Strfy; // The stringified columns PSZ Wrapname; // Java wrapper name int Fpos; // The current row index int N; // The current Rownum diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 2db42cc8cbf..7eff0a68c4b 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -58,6 +58,7 @@ USETEMP UseTemp(void); bool JsonAllPath(void); int GetDefaultDepth(void); char *GetJsonNull(void); +bool Stringified(PCSZ, char*); /***********************************************************************/ /* JSONColumns: construct the result blocks containing the description */ @@ -447,7 +448,7 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j) jcol.Type = TYPE_UNKNOWN; jcol.Len = jcol.Scale = 0; jcol.Cbn = true; - } else if (j < lvl && !(strfy && !stricmp(strfy, colname))) { + } else if (j < lvl && !Stringified(strfy, colname)) { if (!fmt[bf]) strcat(fmt, colname); @@ -517,7 +518,7 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j) } // endswitch Type } else if (lvl >= 0) { - if (strfy && !stricmp(strfy, colname)) { + if (Stringified(strfy, colname)) { if (!fmt[bf]) strcat(fmt, colname); diff --git a/storage/connect/taboccur.cpp b/storage/connect/taboccur.cpp index 6bf2bd2b47f..c63972ec7ab 100644 --- a/storage/connect/taboccur.cpp +++ b/storage/connect/taboccur.cpp @@ -1,7 +1,7 @@ /************ TabOccur CPP Declares Source Code File (.CPP) ************/ /* Name: TABOCCUR.CPP Version 1.2 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2013 - 2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2013 - 2021 */ /* */ /* OCCUR: Table that provides a view of a source table where the */ /* contain of several columns of the source table is placed in only */ @@ -52,8 +52,8 @@ /***********************************************************************/ /* Prepare and count columns in the column list. */ /***********************************************************************/ -static int PrepareColist(char *colist) - { +int PrepareColist(char *colist) +{ char *p, *pn; int n = 0; @@ -71,7 +71,7 @@ static int PrepareColist(char *colist) } // endif p return n; - } // end of PrepareColist +} // end of PrepareColist /************************************************************************/ /* OcrColumns: constructs the result blocks containing all the columns */ @@ -79,7 +79,7 @@ static int PrepareColist(char *colist) /************************************************************************/ bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col, const char *ocr, const char *rank) - { +{ char *pn, *colist; int i, k, m, n = 0, c = 0, j = qrp->Nblin; bool rk, b = false; @@ -168,7 +168,7 @@ bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col, /**********************************************************************/ qrp->Nblin = j; return false; - } // end of OcrColumns +} // end of OcrColumns /************************************************************************/ /* OcrSrcCols: constructs the result blocks containing all the columns */ @@ -176,7 +176,7 @@ bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col, /************************************************************************/ bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col, const char *ocr, const char *rank) - { +{ char *pn, *colist; int i, k, m, n = 0, c = 0; bool rk, b = false; @@ -249,7 +249,7 @@ bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col, /**********************************************************************/ qrp->Nblin = i; return false; - } // end of OcrSrcCols +} // end of OcrSrcCols /* -------------- Implementation of the OCCUR classes ---------------- */ @@ -257,24 +257,24 @@ bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col, /* DefineAM: define specific AM block values from OCCUR table. */ /***********************************************************************/ bool OCCURDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) - { +{ Rcol = GetStringCatInfo(g, "RankCol", ""); Colist = GetStringCatInfo(g, "Colist", ""); Xcol = GetStringCatInfo(g, "OccurCol", Colist); return PRXDEF::DefineAM(g, am, poff); - } // end of DefineAM +} // end of DefineAM /***********************************************************************/ /* GetTable: makes a new TDB of the proper type. */ /***********************************************************************/ PTDB OCCURDEF::GetTable(PGLOBAL g, MODE) - { +{ if (Catfunc != FNC_COL) return new(g) TDBOCCUR(this); else return new(g) TDBTBC(this); - } // end of GetTable +} // end of GetTable /* ------------------------------------------------------------------- */ @@ -282,7 +282,7 @@ PTDB OCCURDEF::GetTable(PGLOBAL g, MODE) /* Implementation of the TDBOCCUR class. */ /***********************************************************************/ TDBOCCUR::TDBOCCUR(POCCURDEF tdp) : TDBPRX(tdp) - { +{ //Tdbp = NULL; // Source table (in TDBPRX) Tabname = tdp->Tablep->GetName(); // Name of source table Colist = tdp->Colist; // List of source columns @@ -294,13 +294,13 @@ TDBOCCUR::TDBOCCUR(POCCURDEF tdp) : TDBPRX(tdp) N = 0; // The current table index M = 0; // The occurence rank RowFlag = 0; // 0: Ok, 1: Same, 2: Skip - } // end of TDBOCCUR constructor +} // end of TDBOCCUR constructor /***********************************************************************/ /* Allocate OCCUR/SRC column description block. */ /***********************************************************************/ PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) - { +{ PCOL colp = NULL; if (!stricmp(cdp->GetName(), Rcolumn)) { @@ -321,13 +321,13 @@ PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) } // endif cprec return colp; - } // end of MakeCol +} // end of MakeCol /***********************************************************************/ /* Initializes the table. */ /***********************************************************************/ bool TDBOCCUR::InitTable(PGLOBAL g) - { +{ if (!Tdbp) // Get the table description block of this table if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE))) @@ -338,13 +338,13 @@ bool TDBOCCUR::InitTable(PGLOBAL g) return TRUE; return FALSE; - } // end of InitTable +} // end of InitTable /***********************************************************************/ /* Allocate OCCUR column description block. */ /***********************************************************************/ bool TDBOCCUR::MakeColumnList(PGLOBAL g) - { +{ char *pn; int i; PCOL colp; @@ -371,13 +371,13 @@ bool TDBOCCUR::MakeColumnList(PGLOBAL g) } // endfor i return false; - } // end of MakeColumnList +} // end of MakeColumnList /***********************************************************************/ /* Allocate OCCUR column description block for a view. */ /***********************************************************************/ bool TDBOCCUR::ViewColumnList(PGLOBAL g) - { +{ char *pn; int i; PCOL colp, cp; @@ -412,13 +412,13 @@ bool TDBOCCUR::ViewColumnList(PGLOBAL g) } // endif Col return false; - } // end of ViewColumnList +} // end of ViewColumnList /***********************************************************************/ /* OCCUR GetMaxSize: returns the maximum number of rows in the table. */ /***********************************************************************/ int TDBOCCUR::GetMaxSize(PGLOBAL g) - { +{ if (MaxSize < 0) { if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE))) return 0; @@ -427,22 +427,22 @@ int TDBOCCUR::GetMaxSize(PGLOBAL g) } // endif MaxSize return MaxSize; - } // end of GetMaxSize +} // end of GetMaxSize /***********************************************************************/ /* In this sample, ROWID will be the (virtual) row number, */ /* while ROWNUM will be the occurence rank in the multiple column. */ /***********************************************************************/ int TDBOCCUR::RowNumber(PGLOBAL, bool b) - { +{ return (b) ? M : N; - } // end of RowNumber +} // end of RowNumber /***********************************************************************/ /* OCCUR Access Method opening routine. */ /***********************************************************************/ bool TDBOCCUR::OpenDB(PGLOBAL g) - { +{ if (Use == USE_OPEN) { /*******************************************************************/ /* Table already open, just replace it at its beginning. */ @@ -491,13 +491,13 @@ bool TDBOCCUR::OpenDB(PGLOBAL g) Use = USE_OPEN; return ViewColumnList(g); - } // end of OpenDB +} // end of OpenDB /***********************************************************************/ /* Data Base read routine for OCCUR access method. */ /***********************************************************************/ int TDBOCCUR::ReadDB(PGLOBAL g) - { +{ int rc = RC_OK; /*********************************************************************/ @@ -518,7 +518,7 @@ int TDBOCCUR::ReadDB(PGLOBAL g) N++; return rc; - } // end of ReadDB +} // end of ReadDB // ------------------------ OCCURCOL functions ---------------------------- @@ -527,17 +527,17 @@ int TDBOCCUR::ReadDB(PGLOBAL g) /***********************************************************************/ OCCURCOL::OCCURCOL(PCOLDEF cdp, PTDBOCCUR tdbp, int n) : COLBLK(cdp, tdbp, n) - { +{ // Set additional OCCUR access method information for column. I = 0; - } // end of OCCURCOL constructor +} // end of OCCURCOL constructor /***********************************************************************/ /* ReadColumn: what this routine does is to access the columns of */ /* list, extract their value and convert it to buffer type. */ /***********************************************************************/ void OCCURCOL::ReadColumn(PGLOBAL g) - { +{ PTDBOCCUR tdbp = (PTDBOCCUR)To_Tdb; PCOL *col = tdbp->Col; @@ -559,7 +559,7 @@ void OCCURCOL::ReadColumn(PGLOBAL g) // Set the OCCUR column value from the Ith source column value Value->SetValue_pval(col[I++]->GetValue()); tdbp->RowFlag = 1; - } // end of ReadColumn +} // end of ReadColumn // ------------------------ RANKCOL functions --------------------------- @@ -569,7 +569,7 @@ void OCCURCOL::ReadColumn(PGLOBAL g) /* list, extract its name and set to it the rank column value. */ /***********************************************************************/ void RANKCOL::ReadColumn(PGLOBAL) - { +{ PTDBOCCUR tdbp = (PTDBOCCUR)To_Tdb; PCOL *col = tdbp->Col; @@ -584,4 +584,4 @@ void RANKCOL::ReadColumn(PGLOBAL) } // endelse - } // end of ReadColumn +} // end of ReadColumn |