PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *cls, bool info) { static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; static unsigned int len, length[] = {0, 6, 8, 10, 10, 6}; int i = 0, n = 0, ncol = sizeof(buftyp) / sizeof(int); int lng, typ, prec; LONG low, upp; BSTR propname; VARIANT val; CIMTYPE type; HRESULT res; PWMIUT wp; SAFEARRAY *prnlist = NULL; PQRYRES qrp = NULL; PCOLRES crp; if (!info) { /*******************************************************************/ /* Initialize WMI if not done yet. */ /*******************************************************************/ if (!(wp = InitWMI(g, nsp, cls))) return NULL; /*******************************************************************/ /* Get the number of properties to return. */ /*******************************************************************/ res = wp->Cobj->Get(bstr_t("__Property_Count"), 0, &val, NULL, NULL); if (FAILED(res)) { sprintf(g->Message, "failed Get(__Property_Count) res=%d\n", res); goto err; } // endif res if (!(n = val.lVal)) { sprintf(g->Message, "Class %s in %s has no properties\n", cls, nsp); goto err; } // endif res /*******************************************************************/ /* Get max property name length. */ /*******************************************************************/ res = wp->Cobj->GetNames(NULL, WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY, NULL, &prnlist); if (FAILED(res)) { sprintf(g->Message, "failed GetNames res=%d\n", res); goto err; } // endif res res = SafeArrayGetLBound(prnlist, 1, &low); res = SafeArrayGetUBound(prnlist, 1, &upp); for (long i = low; i <= upp; i++) { // Get this property name. res = SafeArrayGetElement(prnlist, &i, &propname); if (FAILED(res)) { sprintf(g->Message, "failed GetArrayElement res=%d\n", res); goto err; } // endif res len = (unsigned)SysStringLen(propname); length[0] = MY_MAX(length[0], len); } // enfor i res = SafeArrayDestroy(prnlist); } else length[0] = 128; /*********************************************************************/ /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, buftyp, fldtyp, length, false, true); if (info || !qrp) return qrp; /*********************************************************************/ /* Now get the results into blocks. */ /*********************************************************************/ res = wp->Cobj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY); if (FAILED(res)) { sprintf(g->Message, "failed BeginEnumeration hr=%d\n", res); qrp = NULL; goto err; } // endif hr while (TRUE) { res = wp->Cobj->Next(0, &propname, &val, &type, NULL); if (FAILED(res)) { sprintf(g->Message, "failed getting Next hr=%d\n", res); qrp = NULL; goto err; } else if (res == WBEM_S_NO_MORE_DATA) { VariantClear(&val); break; } // endif res if (i >= n) break; // Should never happen else prec = 0; switch (type) { case CIM_STRING: typ = TYPE_STRING; lng = 255; prec = 1; // Case insensitive break; case CIM_SINT32: case CIM_UINT32: case CIM_BOOLEAN: typ = TYPE_INT; lng = 11; break; case CIM_SINT8: case CIM_UINT8: typ = TYPE_TINY; lng = 4; break; case CIM_SINT16: case CIM_UINT16: typ = TYPE_SHORT; lng = 6; break; case CIM_REAL64: case CIM_REAL32: prec = 2; typ = TYPE_DOUBLE; lng = 15; break; case CIM_SINT64: case CIM_UINT64: typ = TYPE_BIGINT; lng = 20; break; case CIM_DATETIME: typ = TYPE_DATE; lng = 19; break; case CIM_CHAR16: typ = TYPE_STRING; lng = 16; break; case CIM_EMPTY: typ = TYPE_STRING; lng = 24; // ??? break; default: qrp->BadLines++; goto suite; } // endswitch type crp = qrp->Colresp; // Column Name crp->Kdata->SetValue(_com_util::ConvertBSTRToString(propname), i); crp = crp->Next; // Data Type crp->Kdata->SetValue(typ, i); crp = crp->Next; // Type Name crp->Kdata->SetValue(GetTypeName(typ), i); crp = crp->Next; // Precision crp->Kdata->SetValue(lng, i); crp = crp->Next; // Length crp->Kdata->SetValue(lng, i); crp = crp->Next; // Scale (precision) crp->Kdata->SetValue(prec, i); i++; suite: SysFreeString(propname); VariantClear(&val); } // endfor i qrp->Nblin = i; err: // Cleanup wp->Cobj->Release(); wp->Svc->Release(); wp->Svc = NULL; // MUST be set to NULL (why?) CoUninitialize(); /*********************************************************************/ /* Return the result pointer for use by GetData routines. */ /*********************************************************************/ return qrp; } // end of WMIColumns
PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, int hdr, int mxr, bool info) { static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; static unsigned int length[] = {6, 6, 8, 10, 10, 6}; char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096]; int i, imax, hmax, n, nerr, phase, blank, digit, dec, type; int ncol = sizeof(buftyp) / sizeof(int); int num_read = 0, num_max = 10000000; // Statistics int len[MAXCOL], typ[MAXCOL], prc[MAXCOL]; FILE *infile; PQRYRES qrp; PCOLRES crp; if (info) { imax = hmax = 0; length[0] = 128; goto skipit; } // endif info // num_max = atoi(p+1); // Max num of record to test #if defined(WIN32) if (sep == ',' || strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6)) dechar = '.'; else dechar = ','; #else // !WIN32 dechar = '.'; #endif // !WIN32 if (trace) htrc("File %s sep=%c q=%c hdr=%d mxr=%d\n", SVP(fn), sep, q, hdr, mxr); if (!fn) { strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } // endif fn imax = hmax = nerr = 0; mxr = MY_MAX(0, mxr); for (i = 0; i < MAXCOL; i++) { colname[i] = NULL; len[i] = 0; typ[i] = TYPE_UNKNOWN; prc[i] = 0; } // endfor i /*********************************************************************/ /* Open the input file. */ /*********************************************************************/ PlugSetPath(filename, fn, PlgGetDataPath(g)); if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r"))) return NULL; if (hdr) { /*******************************************************************/ /* Make the column names from the first line. */ /*******************************************************************/ phase = 0; if (fgets(buf, sizeof(buf), infile)) { n = strlen(buf) + 1; buf[n - 2] = '\0'; #if defined(UNIX) // The file can be imported from Windows if (buf[n - 3] == '\r') buf[n - 3] = 0; #endif // UNIX p = (char*)PlugSubAlloc(g, NULL, n); memcpy(p, buf, n); //skip leading blanks for (; *p == ' '; p++) ; if (q && *p == q) { // Header is quoted p++; phase = 1; } // endif q colname[0] = p; } else { sprintf(g->Message, MSG(FILE_IS_EMPTY), fn); goto err; } // endif's for (i = 1; *p; p++) if (phase == 1 && *p == q) { *p = '\0'; phase = 0; } else if (*p == sep && !phase) { *p = '\0'; //skip leading blanks for (; *(p+1) == ' '; p++) ; if (q && *(p+1) == q) { // Header is quoted p++; phase = 1; } // endif q colname[i++] = p + 1; } // endif sep num_read++; imax = hmax = i; for (i = 0; i < hmax; i++) length[0] = MY_MAX(length[0], strlen(colname[i])); } // endif hdr for (num_read++; num_read <= num_max; num_read++) { /*******************************************************************/ /* Now start the reading process. Read one line. */ /*******************************************************************/ if (fgets(buf, sizeof(buf), infile)) { n = strlen(buf); buf[n - 1] = '\0'; #if defined(UNIX) // The file can be imported from Windows if (buf[n - 2] == '\r') buf[n - 2] = 0; #endif // UNIX } else if (feof(infile)) { sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1); break; } else { sprintf(g->Message, MSG(ERR_READING_REC), num_read, fn); goto err; } // endif's /*******************************************************************/ /* Make the test for field lengths. */ /*******************************************************************/ i = n = phase = blank = digit = dec = 0; for (p = buf; *p; p++) if (*p == sep) { if (phase != 1) { if (i == MAXCOL - 1) { sprintf(g->Message, MSG(TOO_MANY_FIELDS), num_read, fn); goto err; } // endif i if (n) { len[i] = MY_MAX(len[i], n); type = (digit || (dec && n == 1)) ? TYPE_STRING : (dec) ? TYPE_DOUBLE : TYPE_INT; typ[i] = MY_MIN(type, typ[i]); prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]); } // endif n i++; n = phase = blank = digit = dec = 0; } else // phase == 1 n++; } else if (*p == ' ') { if (phase < 2) n++; if (blank) digit = 1; } else if (*p == q) { if (phase == 0) { if (blank) if (++nerr > mxr) { sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; n = 0; phase = digit = 1; } else if (phase == 1) { if (*(p+1) == q) { // This is currently not implemented for CSV tables // if (++nerr > mxr) { // sprintf(g->Message, MSG(QUOTE_IN_QUOTE), num_read); // goto err; // } else // goto skip; p++; n++; } else phase = 2; } else if (++nerr > mxr) { // phase == 2 sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; } else { if (phase == 2) if (++nerr > mxr) { sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; // isdigit cannot be used here because of debug assert if (!strchr("0123456789", *p)) { if (!digit && *p == dechar) dec = 1; // Decimal point found else if (blank || !(*p == '-' || *p == '+')) digit = 1; } else if (dec) dec++; // More decimals n++; blank = 1; } // endif's *p if (phase == 1) if (++nerr > mxr) { sprintf(g->Message, MSG(UNBALANCE_QUOTE), num_read); goto err; } else goto skip; if (n) { len[i] = MY_MAX(len[i], n); type = (digit || n == 0 || (dec && n == 1)) ? TYPE_STRING : (dec) ? TYPE_DOUBLE : TYPE_INT; typ[i] = MY_MIN(type, typ[i]); prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]); } // endif n imax = MY_MAX(imax, i+1); skip: ; // Skip erroneous line } // endfor num_read if (trace) { htrc("imax=%d Lengths:", imax); for (i = 0; i < imax; i++) htrc(" %d", len[i]); htrc("\n"); } // endif trace fclose(infile); skipit: if (trace) htrc("CSVColumns: imax=%d hmax=%d len=%d\n", imax, hmax, length[0]); /*********************************************************************/ /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3, buftyp, fldtyp, length, false, false); if (info || !qrp) return qrp; qrp->Nblin = imax; /*********************************************************************/ /* Now get the results into blocks. */ /*********************************************************************/ for (i = 0; i < imax; i++) { if (i >= hmax) { sprintf(buf, "COL%.3d", i+1); p = buf; } else p = colname[i]; if (typ[i] == TYPE_UNKNOWN) // Void column typ[i] = TYPE_STRING; crp = qrp->Colresp; // Column Name crp->Kdata->SetValue(p, i); crp = crp->Next; // Data Type crp->Kdata->SetValue(typ[i], i); crp = crp->Next; // Type Name crp->Kdata->SetValue(GetTypeName(typ[i]), i); crp = crp->Next; // Precision crp->Kdata->SetValue(len[i], i); crp = crp->Next; // Length crp->Kdata->SetValue(len[i], i); crp = crp->Next; // Scale (precision) crp->Kdata->SetValue(prc[i], i); } // endfor i /*********************************************************************/ /* Return the result pointer for use by GetData routines. */ /*********************************************************************/ return qrp; err: fclose(infile); return NULL; } // end of CSVCColumns
PQRYRES DBFColumns(PGLOBAL g, char *dp, const char *fn, bool info) { int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; unsigned int length[] = {11, 6, 8, 10, 10, 6}; char buf[2], filename[_MAX_PATH]; int ncol = sizeof(buftyp) / sizeof(int); int rc, type, len, field, fields; bool bad; DBFHEADER mainhead; DESCRIPTOR thisfield; FILE *infile = NULL; PQRYRES qrp; PCOLRES crp; if (trace) htrc("DBFColumns: File %s\n", SVP(fn)); if (!info) { if (!fn) { strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } // endif fn /************************************************************************/ /* Open the input file. */ /************************************************************************/ PlugSetPath(filename, fn, dp); if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb"))) return NULL; /************************************************************************/ /* Get the first 32 bytes of the header. */ /************************************************************************/ if ((rc = dbfhead(g, infile, filename, &mainhead)) == RC_FX) { fclose(infile); return NULL; } // endif dbfhead /************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/ fields = mainhead.Fields; } else fields = 0; qrp = PlgAllocResult(g, ncol, fields, IDS_COLUMNS + 3, buftyp, fldtyp, length, true, false); if (info || !qrp) { if (infile) fclose(infile); return qrp; } // endif info if (trace) { htrc("Structure of %s\n", filename); htrc("headlen=%hd reclen=%hd degree=%d\n", mainhead.Headlen, mainhead.Reclen, fields); htrc("flags(iem)=%d,%d,%d cp=%d\n", mainhead.Incompleteflag, mainhead.Encryptflag, mainhead.Mdxflag, mainhead.Language); htrc("%hd records, last changed %02d/%02d/%d\n", mainhead.Records, mainhead.Filedate[1], mainhead.Filedate[2], mainhead.Filedate[0] + (mainhead.Filedate[0] <= 30) ? 2000 : 1900); htrc("Field Type Offset Len Dec Set Mdx\n"); } // endif trace buf[1] = '\0'; /**************************************************************************/ /* Do it field by field. We are at byte 32 of file. */ /**************************************************************************/ for (field = 0; field < fields; field++) { bad = FALSE; if (fread(&thisfield, HEADLEN, 1, infile) != 1) { sprintf(g->Message, MSG(ERR_READING_REC), field+1, fn); goto err; } else len = thisfield.Length; if (trace) htrc("%-11s %c %6ld %3d %2d %3d %3d\n", thisfield.Name, thisfield.Type, thisfield.Offset, len, thisfield.Decimals, thisfield.Setfield, thisfield.Mdxfield); /************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ switch (thisfield.Type) { case 'C': // Characters case 'L': // Logical 'T' or 'F' type = TYPE_STRING; break; case 'N': type = (thisfield.Decimals) ? TYPE_DOUBLE : (len > 10) ? TYPE_BIGINT : TYPE_INT; break; case 'F': type = TYPE_DOUBLE; break; case 'D': type = TYPE_DATE; // Is this correct ??? break; default: if (!info) { sprintf(g->Message, MSG(BAD_DBF_TYPE), thisfield.Type); goto err; } // endif info type = TYPE_ERROR; bad = TRUE; } // endswitch Type crp = qrp->Colresp; // Column Name crp->Kdata->SetValue(thisfield.Name, field); crp = crp->Next; // Data Type crp->Kdata->SetValue((int)type, field); crp = crp->Next; // Type Name if (bad) { buf[0] = thisfield.Type; crp->Kdata->SetValue(buf, field); } else crp->Kdata->SetValue(GetTypeName(type), field); crp = crp->Next; // Precision crp->Kdata->SetValue((int)thisfield.Length, field); crp = crp->Next; // Length crp->Kdata->SetValue((int)thisfield.Length, field); crp = crp->Next; // Scale (precision) crp->Kdata->SetValue((int)thisfield.Decimals, field); } // endfor field qrp->Nblin = field; fclose(infile); #if 0 if (info) { /************************************************************************/ /* Prepare return message for dbfinfo command. */ /************************************************************************/ char buf[64]; sprintf(buf, "Ver=%02x ncol=%hu nlin=%u lrecl=%hu headlen=%hu date=%02d/%02d/%02d", mainhead.Version, fields, mainhead.Records, mainhead.Reclen, mainhead.Headlen, mainhead.Filedate[0], mainhead.Filedate[1], mainhead.Filedate[2]); strcat(g->Message, buf); } // endif info #endif // 0 /**************************************************************************/ /* Return the result pointer for use by GetData routines. */ /**************************************************************************/ return qrp; err: fclose(infile); return NULL; } // end of DBFColumns
PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, const char *name, bool& info) { int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING, TYPE_STRING, TYPE_STRING}; XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM, FLD_NO, FLD_CHARSET}; unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 32}; char *fld, *colname, *chset, *fmt, v; int i, n, ncol = sizeof(buftyp) / sizeof(int); int prec, len, type, scale; int zconv = GetConvSize(); bool mysql; TABLE_SHARE *s = NULL; Field* *field; Field *fp; PQRYRES qrp; PCOLRES crp; if (!info) { if (!(s = GetTableShare(g, thd, db, name, mysql))) { return NULL; } else if (s->is_view) { strcpy(g->Message, "Use MYSQL type to see columns from a view"); info = true; // To tell caller name is a view free_table_share(s); return NULL; } else n = s->fieldnames.count; } else { n = 0; length[0] = 128; } // endif info /**********************************************************************/ /* Allocate the structures used to refer to the result set. */ /**********************************************************************/ if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, buftyp, fldtyp, length, false, true))) return NULL; // Some columns must be renamed for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) switch (++i) { case 2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break; case 10: crp->Name = "Date_fmt"; break; case 11: crp->Name = "Collation"; break; } // endswitch i if (info) return qrp; /**********************************************************************/ /* Now get the results into blocks. */ /**********************************************************************/ for (i = 0, field= s->field; *field; field++) { fp= *field; // Get column name crp = qrp->Colresp; // Column_Name colname = (char *)fp->field_name; crp->Kdata->SetValue(colname, i); chset = (char *)fp->charset()->name; v = (!strcmp(chset, "binary")) ? 'B' : 0; if ((type = MYSQLtoPLG(fp->type(), &v)) == TYPE_ERROR) { if (v == 'K') { // Skip this column sprintf(g->Message, "Column %s skipped (unsupported type)", colname); push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); continue; } // endif v sprintf(g->Message, "Column %s unsupported type", colname); qrp = NULL; break; } // endif type if (v == 'X') { len = zconv; sprintf(g->Message, "Column %s converted to varchar(%d)", colname, len); push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); } // endif v crp = crp->Next; // Data_Type crp->Kdata->SetValue(type, i); if (fp->flags & ZEROFILL_FLAG) crp->Nulls[i] = 'Z'; else if (fp->flags & UNSIGNED_FLAG) crp->Nulls[i] = 'U'; else // X means TEXT field crp->Nulls[i] = (v == 'X') ? 'V' : v; crp = crp->Next; // Type_Name crp->Kdata->SetValue(GetTypeName(type), i); fmt = NULL; if (type == TYPE_DATE) { // When creating tables we do need info about date columns if (mysql) { fmt = MyDateFmt(fp->type()); prec = len = strlen(fmt); } else { fmt = (char*)fp->option_struct->dateformat; prec = len = fp->field_length; } // endif mysql } else if (v != 'X') { if (type == TYPE_DECIM) prec = ((Field_new_decimal*)fp)->precision; else prec = fp->field_length; // prec = (prec(???) == NOT_FIXED_DEC) ? 0 : fp->field_length; len = fp->char_length(); } else prec = len = zconv; crp = crp->Next; // Precision crp->Kdata->SetValue(prec, i); crp = crp->Next; // Length crp->Kdata->SetValue(len, i); crp = crp->Next; // Scale scale = (type == TYPE_DOUBLE || type == TYPE_DECIM) ? fp->decimals() : 0; crp->Kdata->SetValue(scale, i); crp = crp->Next; // Radix crp->Kdata->SetValue(0, i); crp = crp->Next; // Nullable crp->Kdata->SetValue((fp->null_ptr != 0) ? 1 : 0, i); crp = crp->Next; // Remark // For Valgrind if (fp->comment.length > 0 && (fld = fp->comment.str)) crp->Kdata->SetValue(fld, fp->comment.length, i); else crp->Kdata->Reset(i); crp = crp->Next; // New (date format) crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i); crp = crp->Next; // New (charset) fld = (char *)fp->charset()->name; crp->Kdata->SetValue(fld, i); // Add this item qrp->Nblin++; i++; // Can be skipped } // endfor field /**********************************************************************/ /* Return the result pointer for use by GetData routines. */ /**********************************************************************/ if (s) free_table_share(s); return qrp; } // end of TabColumns
PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db, const char *user, const char *pwd, const char *table, const char *colpat, int port, bool info) { int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING}; XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_KEY, FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM, FLD_NO, FLD_DEFAULT, FLD_EXTRA, FLD_CHARSET}; unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0}; char *fld, *colname, *chset, *fmt, v, buf[128], uns[16], zero[16]; int i, n, nf, ncol = sizeof(buftyp) / sizeof(int); int len, type, prec, rc, k = 0; PQRYRES qrp; PCOLRES crp; MYSQLC myc; if (!port) port = mysqld_port; if (!info) { /********************************************************************/ /* Open the connection with the MySQL server. */ /********************************************************************/ if (myc.Open(g, host, db, user, pwd, port)) return NULL; /********************************************************************/ /* Do an evaluation of the result size. */ /********************************************************************/ STRING cmd(g, 64, "SHOW FULL COLUMNS FROM "); bool b = cmd.Append((PSZ)table); b |= cmd.Append(" FROM "); b |= cmd.Append((PSZ)(db ? db : PlgGetUser(g)->DBName)); if (colpat) { b |= cmd.Append(" LIKE "); b |= cmd.Append((PSZ)colpat); } // endif colpat if (b) { strcpy(g->Message, "Out of memory"); return NULL; } // endif b if (trace) htrc("MyColumns: cmd='%s'\n", cmd.GetStr()); if ((n = myc.GetResultSize(g, cmd.GetStr())) < 0) { myc.Close(); return NULL; } // endif n /********************************************************************/ /* Get the size of the name and default columns. */ /********************************************************************/ length[0] = myc.GetFieldLength(0); // length[10] = myc.GetFieldLength(5); } else { n = 0; length[0] = 128; } // endif info /**********************************************************************/ /* Allocate the structures used to refer to the result set. */ /**********************************************************************/ if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, buftyp, fldtyp, length, false, true))) return NULL; // Some columns must be renamed for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) switch (++i) { case 2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break; case 4: crp->Name = "Length"; break; case 5: crp->Name = "Key"; break; case 10: crp->Name = "Date_fmt"; break; case 11: crp->Name = "Default"; break; case 12: crp->Name = "Extra"; break; case 13: crp->Name = "Collation"; break; } // endswitch i if (info) return qrp; /**********************************************************************/ /* Now get the results into blocks. */ /**********************************************************************/ for (i = 0; i < n; /*i++*/) { if ((rc = myc.Fetch(g, -1)) == RC_FX) { myc.Close(); return NULL; } else if (rc == RC_EF) break; // Get column name colname = myc.GetCharField(0); crp = qrp->Colresp; // Column_Name crp->Kdata->SetValue(colname, i); // Get type, type name, precision, unsigned and zerofill chset = myc.GetCharField(2); fld = myc.GetCharField(1); prec = 0; len = 0; v = (chset && !strcmp(chset, "binary")) ? 'B' : 0; *uns = 0; *zero = 0; switch ((nf = sscanf(fld, "%[^(](%d,%d", buf, &len, &prec))) { case 3: nf = sscanf(fld, "%[^(](%d,%d) %s %s", buf, &len, &prec, uns, zero); break; case 2: nf = sscanf(fld, "%[^(](%d) %s %s", buf, &len, uns, zero) + 1; break; case 1: nf = sscanf(fld, "%s %s %s", buf, uns, zero) + 2; break; default: sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld); myc.Close(); return NULL; } // endswitch nf if ((type = MYSQLtoPLG(buf, &v)) == TYPE_ERROR) { if (v == 'K') { // Skip this column sprintf(g->Message, "Column %s skipped (unsupported type %s)", colname, buf); PushWarning(g, thd); continue; } // endif v sprintf(g->Message, "Column %s unsupported type %s", colname, buf); myc.Close(); return NULL; } else if (type == TYPE_STRING) { if (v == 'X') { len = GetConvSize(); sprintf(g->Message, "Column %s converted to varchar(%d)", colname, len); PushWarning(g, thd); v = 'V'; } else len = MY_MIN(len, 4096); } // endif type qrp->Nblin++; crp = crp->Next; // Data_Type crp->Kdata->SetValue(type, i); switch (nf) { case 5: crp->Nulls[i] = 'Z'; break; case 4: crp->Nulls[i] = 'U'; break; default: crp->Nulls[i] = v; break; } // endswitch nf crp = crp->Next; // Type_Name crp->Kdata->SetValue(buf, i); if (type == TYPE_DATE) { // When creating tables we do need info about date columns fmt = MyDateFmt(buf); len = strlen(fmt); } else fmt = NULL; crp = crp->Next; // Precision crp->Kdata->SetValue(len, i); crp = crp->Next; // key (was Length) fld = myc.GetCharField(4); crp->Kdata->SetValue(fld, i); crp = crp->Next; // Scale crp->Kdata->SetValue(prec, i); crp = crp->Next; // Radix crp->Kdata->SetValue(0, i); crp = crp->Next; // Nullable fld = myc.GetCharField(3); crp->Kdata->SetValue((toupper(*fld) == 'Y') ? 1 : 0, i); crp = crp->Next; // Remark fld = myc.GetCharField(8); crp->Kdata->SetValue(fld, i); crp = crp->Next; // Date format // crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i); crp->Kdata->SetValue(fmt, i); crp = crp->Next; // New (default) fld = myc.GetCharField(5); crp->Kdata->SetValue(fld, i); crp = crp->Next; // New (extra) fld = myc.GetCharField(6); crp->Kdata->SetValue(fld, i); crp = crp->Next; // New (charset) fld = chset; crp->Kdata->SetValue(fld, i); i++; // Can be skipped } // endfor i #if 0 if (k > 1) { // Multicolumn primary key PVBLK vbp = qrp->Colresp->Next->Next->Next->Next->Kdata; for (i = 0; i < n; i++) if (vbp->GetIntValue(i)) vbp->SetValue(k, i); } // endif k #endif // 0 /**********************************************************************/ /* Close MySQL connection. */ /**********************************************************************/ myc.Close(); /**********************************************************************/ /* Return the result pointer for use by GetData routines. */ /**********************************************************************/ return qrp; } // end of MyColumns