diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp index 2953fa29493..6b2921e1737 100644 --- a/storage/connect/colblk.cpp +++ b/storage/connect/colblk.cpp @@ -41,6 +41,7 @@ COLBLK::COLBLK(PCOLDEF cdp, PTDB tdbp, int i) Buf_Type = cdp->Buf_Type; ColUse |= cdp->Flags; // Used by CONNECT Nullable = !!(cdp->Flags & U_NULLS); + Unsigned = !!(cdp->Flags & U_UNSIGNED); } else { Name = NULL; memset(&Format, 0, sizeof(FORMAT)); @@ -48,6 +49,7 @@ COLBLK::COLBLK(PCOLDEF cdp, PTDB tdbp, int i) Long = 0; Buf_Type = TYPE_ERROR; Nullable = false; + Unsigned = false; } // endif cdp To_Tdb = tdbp; @@ -171,9 +173,12 @@ bool COLBLK::InitValue(PGLOBAL g) if (Value) return false; // Already done + // Unsigned can be set only for valid value types + int prec = (Unsigned) ? 1 : GetPrecision(); + // Allocate a Value object if (!(Value = AllocateValue(g, Buf_Type, Format.Length, - GetPrecision(), GetDomain()))) + prec, GetDomain()))) return true; AddStatus(BUF_READY); diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index a5771ccc6fa..7b5fe0cad0f 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -83,6 +83,7 @@ class DllExport COLBLK : public XOBJECT { PTDB To_Tdb; // Points to Table Descriptor Block PXCOL To_Kcol; // Points to Xindex matching column bool Nullable; // True if nullable + bool Unsigned; // True if unsigned int Index; // Column number in table int Opt; // Cluster/sort information int Buf_Type; // Data type diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index fd5f6fe6d5d..688e7c092c1 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -685,6 +685,7 @@ RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op, char *kp= (char*)key; int n; short lg; + bool rcb; RCODE rc; PVAL valp; PCOL colp; @@ -719,9 +720,20 @@ RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op, if (colp->GetColUse(U_VAR)) { lg= *(short*)kp; kp+= sizeof(short); - valp->SetValue_char(kp, (int)lg); + rcb= valp->SetValue_char(kp, (int)lg); } else - valp->SetValue_char(kp, valp->GetClen()); + rcb= valp->SetValue_char(kp, valp->GetClen()); + + if (rcb) { + if (tdbp->RowNumber(g)) + sprintf(g->Message, "Out of range value for column %s at row %d", + colp->GetName(), tdbp->RowNumber(g)); + else + sprintf(g->Message, "Out of range value for column %s", + colp->GetName()); + + PushWarning(g, tdbp); + } // endif b } else valp->SetBinValue((void*)kp); @@ -759,7 +771,7 @@ int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, const uchar *p, *kp; int i, n, k[2]; short lg; - bool b; + bool b, rcb; PVAL valp; PCOL colp; PTDBDOX tdbp; @@ -802,9 +814,21 @@ int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, if (colp->GetColUse(U_VAR)) { lg= *(short*)p; p+= sizeof(short); - valp->SetValue_char((char*)p, (int)lg); + rcb= valp->SetValue_char((char*)p, (int)lg); } else - valp->SetValue_char((char*)p, valp->GetClen()); + rcb= valp->SetValue_char((char*)p, valp->GetClen()); + + if (rcb) { + if (tdbp->RowNumber(g)) + sprintf(g->Message, + "Out of range value for column %s at row %d", + colp->GetName(), tdbp->RowNumber(g)); + else + sprintf(g->Message, "Out of range value for column %s", + colp->GetName()); + + PushWarning(g, tdbp); + } // endif b } else valp->SetBinValue((void*)p); diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 038fb05839a..f9a9fac11cc 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -165,7 +165,7 @@ extern "C" char nmfile[]; extern "C" char pdebug[]; extern "C" { - char version[]= "Version 1.01.0009 October 29, 2013"; + char version[]= "Version 1.01.0010 November 30, 2013"; #if defined(XMSG) char msglang[]; // Default message language @@ -777,7 +777,7 @@ int ha_connect::GetIntegerOption(char *opname) if (opval == (ulonglong)NO_IVAL && options && options->oplist) if ((pv= GetListOption(xp->g, opname, options->oplist))) - opval= (unsigned)atoll(pv); + opval= CharToNumber(pv, strlen(pv), ULONGLONG_MAX, true); return (int)opval; } // end of GetIntegerOption @@ -936,6 +936,12 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) break; } // endswitch type + if (fp->flags & UNSIGNED_FLAG) + pcf->Flags |= U_UNSIGNED; + + if (fp->flags & ZEROFILL_FLAG) + pcf->Flags |= U_ZEROFILL; + // This is used to skip null bit if (fp->real_maybe_null()) pcf->Flags |= U_NULLS; @@ -1341,7 +1347,15 @@ int ha_connect::MakeRecord(char *buf) } else if (fp->store(value->GetFloatValue())) { - rc= HA_ERR_WRONG_IN_RECORD; +// rc= HA_ERR_WRONG_IN_RECORD; a Warning was ignored + char buf[128]; + THD *thd= ha_thd(); + + sprintf(buf, "Out of range value for column '%s' at row %ld", + fp->field_name, + thd->get_stmt_da()->current_row_for_warning()); + + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, buf); DBUG_PRINT("MakeRecord", ("%s", value->GetCharString(val))); } // endif store @@ -3511,7 +3525,7 @@ static bool add_fields(PGLOBAL g, #else // !NEW_WAY static bool add_field(String *sql, const char *field_name, int typ, int len, int dec, uint tm, const char *rem, - int flag, bool dbf, char v) + char *dft, int flag, bool dbf, char v) { char var = (len > 255) ? 'V' : v; bool error= false; @@ -3535,9 +3549,26 @@ static bool add_field(String *sql, const char *field_name, int typ, error|= sql->append(')'); } // endif len + if (v == 'U') + error|= sql->append(" UNSIGNED"); + else if (v == 'Z') + error|= sql->append(" ZEROFILL"); + if (tm) error|= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info); + if (dft && *dft) { + error|= sql->append(" DEFAULT "); + + if (IsTypeChar(typ)) { + error|= sql->append("'"); + error|= sql->append_for_single_quote(dft, strlen(dft)); + error|= sql->append("'"); + } else + error|= sql->append(dft); + + } // endif rem + if (rem && *rem) { error|= sql->append(" COMMENT '"); error|= sql->append_for_single_quote(rem, strlen(rem)); @@ -4044,8 +4075,8 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, } // endif src if (ok) { - char *cnm, *rem; - int i, len, dec, typ, flg; + char *cnm, *rem, *dft; + int i, len, prec, dec, typ, flg; PDBUSER dup= PlgGetUser(g); PCATLG cat= (dup) ? dup->Catalog : NULL; @@ -4154,16 +4185,17 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, NOT_NULL_FLAG, "", flg, dbf); #else // !NEW_WAY // Now add the field - if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG, 0, flg, dbf, 0)) + if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG, 0, NULL, flg, dbf, 0)) rc= HA_ERR_OUT_OF_MEM; #endif // !NEW_WAY } // endfor crp } else // Not a catalog table for (i= 0; !rc && i < qrp->Nblin; i++) { - typ= len= dec= 0; + typ= len= prec= dec= 0; tm= NOT_NULL_FLAG; cnm= (char*)"noname"; + dft= NULL; #if defined(NEW_WAY) rem= ""; // cs= NULL; @@ -4181,6 +4213,10 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, v = (crp->Nulls) ? crp->Nulls[i] : 0; break; case FLD_PREC: + // PREC must be always before LENGTH + len= prec= crp->Kdata->GetIntValue(i); + break; + case FLD_LENGTH: len= crp->Kdata->GetIntValue(i); break; case FLD_SCALE: @@ -4200,6 +4236,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, // cs= get_charset_by_name(csn, 0); // break; + case FLD_DEFAULT: + dft= crp->Kdata->GetCharValue(i); + break; default: break; // Ignore } // endswitch Fld @@ -4209,16 +4248,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, int plgtyp; // typ must be PLG type, not SQL type - if (!(plgtyp= TranslateSQLType(typ, dec, len, v))) { + if (!(plgtyp= TranslateSQLType(typ, dec, prec, v))) { sprintf(g->Message, "Unsupported SQL type %d", typ); my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); return HA_ERR_INTERNAL_ERROR; } else typ= plgtyp; - // Some data sources do not count dec in length + // Some data sources do not count dec in length (prec) if (typ == TYPE_FLOAT) - len += (dec + 2); // To be safe + prec += (dec + 2); // To be safe else dec= 0; @@ -4227,14 +4266,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, // Make the arguments as required by add_fields if (typ == TYPE_DATE) - len= 0; + prec= 0; + else if (typ == TYPE_FLOAT) + prec= len; // Now add the field #if defined(NEW_WAY) rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec, tm, rem, 0, true); #else // !NEW_WAY - if (add_field(&sql, cnm, typ, len, dec, tm, rem, 0, dbf, v)) + if (add_field(&sql, cnm, typ, prec, dec, tm, rem, dft, 0, dbf, v)) rc= HA_ERR_OUT_OF_MEM; #endif // !NEW_WAY } // endfor i diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index f9763f0eb2f..d2a130e103f 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -46,21 +46,6 @@ #define DLL_EXPORT // Items are exported from this DLL #include "myconn.h" -#if defined(EMBEDDED) -static char *server_args[] = { - "this_program", /* this string is not used */ - "--skip-bdb", - "--skip-innodb" - }; - -static char *server_groups[] = { - "PlugDB_SERVER", - "embedded", - "server", - (char *)NULL - }; -#endif // EMBEDDED - extern "C" int trace; extern MYSQL_PLUGIN_IMPORT uint mysqld_port; @@ -82,12 +67,12 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, { static 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, TYPE_STRING, TYPE_STRING}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_KEY, FLD_SCALE, FLD_RADIX, FLD_NULL, - FLD_REM, FLD_NO, FLD_CHARSET}; - static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 256, 32, 32}; - char *fld, *fmt, v, cmd[128]; + FLD_REM, FLD_NO, FLD_DEFAULT, FLD_CHARSET}; + static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 0, 32}; + char *fld, *fmt, v, cmd[128], uns[16], zero[16]; int i, n, nf, ncol = sizeof(buftyp) / sizeof(int); int len, type, prec, rc, k = 0; PQRYRES qrp; @@ -122,9 +107,10 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, } // endif n /********************************************************************/ - /* Get the size of the name columns. */ + /* 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; @@ -164,18 +150,29 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, crp = qrp->Colresp; // Column_Name crp->Kdata->SetValue(fld, i); - // Get type, type name, and precision + // Get type, type name, precision, unsigned and zerofill fld = myc.GetCharField(1); prec = 0; len = 0; v = 0; + *uns = 0; + *zero = 0; - if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) { - sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld); - myc.Close(); - return NULL; - } else - qrp->Nblin++; + switch ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec))) { + case 3: + nf = sscanf(fld, "%[^(](%d,%d) %s %s", cmd, &len, &prec, uns, zero); + break; + case 2: + nf = sscanf(fld, "%[^(](%d) %s %s", cmd, &len, uns, zero) + 1; + break; + case 1: + nf = sscanf(fld, "%s %s %s", cmd, uns, zero) + 2; + break; + default: + sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld); + myc.Close(); + return NULL; + } // endswitch nf if ((type = MYSQLtoPLG(cmd, &v)) == TYPE_ERROR) { sprintf(g->Message, "Unsupported column type %s", cmd); @@ -184,9 +181,16 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, } else if (type == TYPE_STRING) len = min(len, 4096); + qrp->Nblin++; crp = crp->Next; // Data_Type crp->Kdata->SetValue(type, i); - crp->Nulls[i] = v; + + 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(cmd, i); @@ -200,7 +204,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, crp = crp->Next; // Precision crp->Kdata->SetValue(len, i); - crp = crp->Next; // was Length + crp = crp->Next; // key (was Length) fld = myc.GetCharField(4); crp->Kdata->SetValue(fld, i); @@ -218,9 +222,13 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, fld = myc.GetCharField(8); crp->Kdata->SetValue(fld, i); - crp = crp->Next; // New + crp = crp->Next; // Date format crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i); + crp = crp->Next; // New (default) + fld = myc.GetCharField(5); + crp->Kdata->SetValue(fld, i); + crp = crp->Next; // New (charset) fld = myc.GetCharField(2); crp->Kdata->SetValue(fld, i); @@ -657,6 +665,7 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb) { char *fmt; int n; + bool uns; PCOLRES *pcrp, crp; PQRYRES qrp; MYSQL_FIELD *fld; @@ -707,9 +716,10 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb) crp->Prec = (crp->Type == TYPE_FLOAT) ? fld->decimals : 0; crp->Length = fld->max_length; crp->Clen = GetTypeSize(crp->Type, crp->Length); + uns = (fld->flags & (UNSIGNED_FLAG | ZEROFILL_FLAG)) ? true : false; if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows, - crp->Clen, 0, FALSE, TRUE, FALSE))) { + crp->Clen, 0, FALSE, TRUE, uns))) { sprintf(g->Message, MSG(INV_RESULT_TYPE), GetFormatType(crp->Type)); return NULL; diff --git a/storage/connect/mysql-test/connect/r/mysql_discovery.result b/storage/connect/mysql-test/connect/r/mysql_discovery.result index 2fc2039e53e..04c902d983a 100644 --- a/storage/connect/mysql-test/connect/r/mysql_discovery.result +++ b/storage/connect/mysql-test/connect/r/mysql_discovery.result @@ -15,7 +15,7 @@ t1 CREATE TABLE `t1` ( `id` int(20) NOT NULL, `group` int(11) NOT NULL, `a\\b` int(11) NOT NULL, - `a\\` int(10) DEFAULT NULL, + `a\\` int(10) unsigned DEFAULT NULL, `name` varchar(32) DEFAULT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`='MYSQL' INSERT INTO t1 (id, name) VALUES (1, 'foo'); diff --git a/storage/connect/mysql-test/connect/r/unsigned.result b/storage/connect/mysql-test/connect/r/unsigned.result new file mode 100644 index 00000000000..9f4a4470721 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/unsigned.result @@ -0,0 +1,73 @@ +# +# Testing unsigned types +# +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 'test.t1' +CREATE TABLE t1 ( +a TINYINT UNSIGNED NOT NULL, +b SMALLINT ZEROFILL NOT NULL, +c INT UNSIGNED NOT NULL, +d BIGINT UNSIGNED NOT NULL, +e CHAR(32) NOT NULL DEFAULT '???') ENGINE=CONNECT TABLE_TYPE=FIX; +Warnings: +Warning 1105 No file name. Table will use t1.fix +DESCRIBE t1; +Field Type Null Key Default Extra +a tinyint(3) unsigned NO NULL +b smallint(5) unsigned zerofill NO NULL +c int(10) unsigned NO NULL +d bigint(20) unsigned NO NULL +e char(32) NO ??? +INSERT INTO t1(a,b,c,d) VALUES(255,65535,4294967295,18446744073709551615); +SELECT * FROM t1; +a b c d e +255 65535 4294967295 18446744073709551615 ??? +UPDATE t1 SET e = d; +SELECT * FROM t1; +a b c d e +255 65535 4294967295 18446744073709551615 18446744073709551615 +UPDATE t1 SET c = d; +Warnings: +Warning 1264 Out of range value for column 'c' at row 1 +SELECT * FROM t1; +a b c d e +255 65535 4294967295 18446744073709551615 18446744073709551615 +UPDATE t1 SET c = e; +Warnings: +Warning 1264 Out of range value for column 'c' at row 1 +SELECT * FROM t1; +a b c d e +255 65535 4294967295 18446744073709551615 18446744073709551615 +UPDATE t1 SET d = e; +SELECT * FROM t1; +a b c d e +255 65535 4294967295 18446744073709551615 18446744073709551615 +DROP TABLE IF EXISTS t2; +Warnings: +Note 1051 Unknown table 'test.t2' +CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME=t1; +DESCRIBE t2; +Field Type Null Key Default Extra +a tinyint(3) unsigned NO NULL +b smallint(5) unsigned zerofill NO NULL +c int(10) unsigned NO NULL +d bigint(20) unsigned NO NULL +e char(32) NO NULL +SELECT * FROM t2; +a b c d e +255 65535 4294967295 18446744073709551615 18446744073709551615 +DROP TABLE t2; +CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME=t1; +DESCRIBE t2; +Field Type Null Key Default Extra +a tinyint(3) unsigned NO NULL +b smallint(5) unsigned zerofill NO NULL +c int(10) unsigned NO NULL +d bigint(20) unsigned NO NULL +e char(32) NO ??? +SELECT * FROM t2; +a b c d e +255 65535 4294967295 18446744073709551615 18446744073709551615 +DROP TABLE t2; +DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result index a8d2ded7bcf..e952cc3a635 100644 --- a/storage/connect/mysql-test/connect/r/xml.result +++ b/storage/connect/mysql-test/connect/r/xml.result @@ -413,7 +413,7 @@ DROP TABLE t1; SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); SELECT CAST(@a AS CHAR CHARACTER SET latin1); CAST(@a AS CHAR CHARACTER SET latin1) - + ÀÁÂÃ diff --git a/storage/connect/mysql-test/connect/t/unsigned.test b/storage/connect/mysql-test/connect/t/unsigned.test new file mode 100644 index 00000000000..5119142ba52 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/unsigned.test @@ -0,0 +1,34 @@ +--echo # +--echo # Testing unsigned types +--echo # +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +a TINYINT UNSIGNED NOT NULL, +b SMALLINT ZEROFILL NOT NULL, +c INT UNSIGNED NOT NULL, +d BIGINT UNSIGNED NOT NULL, +e CHAR(32) NOT NULL DEFAULT '???') ENGINE=CONNECT TABLE_TYPE=FIX; +DESCRIBE t1; +INSERT INTO t1(a,b,c,d) VALUES(255,65535,4294967295,18446744073709551615); +SELECT * FROM t1; +UPDATE t1 SET e = d; +SELECT * FROM t1; +UPDATE t1 SET c = d; +SELECT * FROM t1; +UPDATE t1 SET c = e; +SELECT * FROM t1; +UPDATE t1 SET d = e; +SELECT * FROM t1; + +DROP TABLE IF EXISTS t2; +CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME=t1; +DESCRIBE t2; +SELECT * FROM t2; + +DROP TABLE t2; +CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME=t1; +DESCRIBE t2; +SELECT * FROM t2; + +DROP TABLE t2; +DROP TABLE t1; diff --git a/storage/connect/myutil.cpp b/storage/connect/myutil.cpp index 1b6cbaa84c7..9588a45ee8a 100644 --- a/storage/connect/myutil.cpp +++ b/storage/connect/myutil.cpp @@ -143,7 +143,7 @@ const char *PLGtoMYSQLtype(int type, bool dbf, char v) /************************************************************************/ /* Convert from MySQL type to PlugDB type number */ /************************************************************************/ -int MYSQLtoPLG(int mytype) +int MYSQLtoPLG(int mytype, char *var) { int type; @@ -177,7 +177,6 @@ int MYSQLtoPLG(int mytype) case MYSQL_TYPE_TIME: type = TYPE_DATE; break; - case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: #if !defined(ALPHA) case MYSQL_TYPE_VARCHAR: @@ -186,6 +185,8 @@ int MYSQLtoPLG(int mytype) case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: + if (var) *var = 'V'; + case MYSQL_TYPE_STRING: type = TYPE_STRING; break; default: diff --git a/storage/connect/myutil.h b/storage/connect/myutil.h index 46f060e3e17..f5faeec1127 100644 --- a/storage/connect/myutil.h +++ b/storage/connect/myutil.h @@ -7,7 +7,7 @@ enum enum_field_types PLGtoMYSQL(int type, bool dbf); const char *PLGtoMYSQLtype(int type, bool dbf, char var = NULL); int MYSQLtoPLG(char *typname, char *var = NULL); -int MYSQLtoPLG(int mytype); +int MYSQLtoPLG(int mytype, char *var = NULL); char *MyDateFmt(int mytype); char *MyDateFmt(char *typname); diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index d8f27603f6c..9e9d84d4a28 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -330,7 +330,9 @@ enum COLUSE {U_P = 0x01, /* the projection list. */ U_VIRTUAL = 0x20, /* a VIRTUAL column */ U_NULLS = 0x40, /* The column may have nulls */ U_IS_NULL = 0x80, /* The column has a null value */ - U_SPECIAL = 0x100}; /* The column is special */ + U_SPECIAL = 0x100, /* The column is special */ + U_UNSIGNED = 0x200, /* The column type is unsigned */ + U_ZEROFILL = 0x400}; /* The column is zero filled */ /***********************************************************************/ /* DB description class and block pointer definitions. */ diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 72b3a27b057..2baf9de155f 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -1087,7 +1087,12 @@ void DOSCOL::ReadColumn(PGLOBAL g) case TYPE_SHORT: case TYPE_TINY: case TYPE_BIGINT: - Value->SetValue_char(p, field - Dcm); + if (Value->SetValue_char(p, field - Dcm)) { + sprintf(g->Message, "Out of range value for column %s at row %d", + Name, tdbp->RowNumber(g)); + PushWarning(g, tdbp); + } // endif SetValue_char + break; case TYPE_FLOAT: Value->SetValue_char(p, field); @@ -1104,7 +1109,11 @@ void DOSCOL::ReadColumn(PGLOBAL g) } // endswitch Buf_Type else - Value->SetValue_char(p, field); + if (Value->SetValue_char(p, field)) { + sprintf(g->Message, "Out of range value for column %s at row %d", + Name, tdbp->RowNumber(g)); + PushWarning(g, tdbp); + } // endif SetValue_char break; default: diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp index 4cad405452e..2358dc07638 100644 --- a/storage/connect/tabfix.cpp +++ b/storage/connect/tabfix.cpp @@ -375,7 +375,12 @@ void BINCOL::ReadColumn(PGLOBAL g) Value->SetValue(*(double*)p); break; case 'C': // Text - Value->SetValue_char(p, Long); + if (Value->SetValue_char(p, Long)) { + sprintf(g->Message, "Out of range value for column %s at row %d", + Name, tdbp->RowNumber(g)); + PushWarning(g, tdbp); + } // endif SetValue_char + break; default: sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name); diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 7db44658058..12b206a911a 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -1284,13 +1284,18 @@ void MYSQLCOL::ReadColumn(PGLOBAL g) htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf); // TODO: have a true way to differenciate temporal values - if (strlen(buf) == 8) + if (Buf_Type == TYPE_DATE && strlen(buf) == 8) // This is a TIME value p = strcat(strcpy(tim, "1970-01-01 "), buf); else p = buf; - Value->SetValue_char(p, strlen(p)); + if (Value->SetValue_char(p, strlen(p))) { + sprintf(g->Message, "Out of range value for column %s at row %d", + Name, tdbp->RowNumber(g)); + PushWarning(g, tdbp); + } // endif SetValue_char + } else { if (Nullable) Value->SetNull(true); diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp index fa4c8667a70..8b1b8555f53 100644 --- a/storage/connect/tabutil.cpp +++ b/storage/connect/tabutil.cpp @@ -117,7 +117,7 @@ TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db, /************************************************************************/ /* TabColumns: constructs the result blocks containing all the columns */ -/* of the object table that will be retrieved by GetData commands. */ +/* description of the object table that will be retrieved by discovery.*/ /************************************************************************/ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, const char *name, bool& info) @@ -128,8 +128,8 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM, FLD_NO, FLD_CHARSET}; - static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 256, 32, 32}; - char *fld, *fmt; + static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 32}; + char *fld, *fmt, v; int i, n, ncol = sizeof(buftyp) / sizeof(int); int len, type, prec; bool mysql; @@ -164,6 +164,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, // 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 @@ -181,8 +182,9 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, crp = qrp->Colresp; // Column_Name fld = (char *)fp->field_name; crp->Kdata->SetValue(fld, i); + v = 0; - if ((type = MYSQLtoPLG(fp->type())) == TYPE_ERROR) { + if ((type = MYSQLtoPLG(fp->type(), &v)) == TYPE_ERROR) { sprintf(g->Message, "Unsupported column type %s", GetTypeName(type)); qrp = NULL; break; @@ -190,6 +192,14 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, 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 + crp->Nulls[i] = v; + crp = crp->Next; // Type_Name crp->Kdata->SetValue(GetTypeName(type), i); @@ -200,7 +210,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, len = strlen(fmt); } else { fmt = (char*)fp->option_struct->dateformat; - len = fp->field_length; + fp->field_length; } // endif mysql } else { @@ -212,10 +222,10 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, crp->Kdata->SetValue(len, i); crp = crp->Next; // Length - len = fp->field_length; + prec = (type == TYPE_FLOAT) ? fp->decimals() : 0; + len = (prec == 31) ? 0 : fp->field_length; crp->Kdata->SetValue(len, i); - prec = (type == TYPE_FLOAT) ? fp->decimals() : 0; crp = crp->Next; // Scale crp->Kdata->SetValue(prec, i); @@ -233,7 +243,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, else crp->Kdata->Reset(i); - crp = crp->Next; // New + crp = crp->Next; // New (date format) crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i); crp = crp->Next; // New (charset) diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index 7fabad88794..afaff491249 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -191,7 +191,7 @@ void VALBLK::ChkIndx(int n) void VALBLK::ChkTyp(PVAL v) { - if (Check && Type != v->GetType()) { + if (Check && (Type != v->GetType() || Unsigned != v->IsUnsigned())) { PGLOBAL& g = Global; strcpy(g->Message, MSG(VALTYPE_NOMATCH)); longjmp(g->jumper[g->jump_level], Type); @@ -201,7 +201,7 @@ void VALBLK::ChkTyp(PVAL v) void VALBLK::ChkTyp(PVBLK vb) { - if (Check && Type != vb->GetType()) { + if (Check && (Type != vb->GetType() || Unsigned != vb->IsUnsigned())) { PGLOBAL& g = Global; strcpy(g->Message, MSG(VALTYPE_NOMATCH)); longjmp(g->jumper[g->jump_level], Type); @@ -304,28 +304,44 @@ void TYPBLK::SetValue(PSZ p, int n) longjmp(g->jumper[g->jump_level], Type); } // endif Check - Typp[n] = GetTypedValue(p); + bool minus; + ulonglong maxval = MaxVal(); + ulonglong val = CharToNumber(p, strlen(p), maxval, Unsigned, &minus); + + if (minus && val < maxval) + Typp[n] = (TYPE)(-(signed)val); + else + Typp[n] = (TYPE)val; + SetNull(n, false); } // end of SetValue +template +ulonglong TYPBLK::MaxVal(void) {DBUG_ASSERT(false); return 0;} + template <> -int TYPBLK::GetTypedValue(PSZ p) {return atol(p);} +ulonglong TYPBLK::MaxVal(void) {return INT_MAX16;} + template <> -uint TYPBLK::GetTypedValue(PSZ p) {return (unsigned)atol(p);} +ulonglong TYPBLK::MaxVal(void) {return UINT_MAX16;} + template <> -short TYPBLK::GetTypedValue(PSZ p) {return (short)atoi(p);} +ulonglong TYPBLK::MaxVal(void) {return INT_MAX32;} + template <> -ushort TYPBLK::GetTypedValue(PSZ p) {return (ushort)atoi(p);} +ulonglong TYPBLK::MaxVal(void) {return UINT_MAX32;} + template <> -longlong TYPBLK::GetTypedValue(PSZ p) {return atoll(p);} +ulonglong TYPBLK::MaxVal(void) {return INT_MAX8;} + template <> -ulonglong TYPBLK::GetTypedValue(PSZ p) {return (unsigned)atoll(p);} +ulonglong TYPBLK::MaxVal(void) {return UINT_MAX8;} + template <> -double TYPBLK::GetTypedValue(PSZ p) {return atof(p);} +ulonglong TYPBLK::MaxVal(void) {return INT_MAX64;} + template <> -char TYPBLK::GetTypedValue(PSZ p) {return (char)atoi(p);} -template <> -uchar TYPBLK::GetTypedValue(PSZ p) {return (uchar)atoi(p);} +ulonglong TYPBLK::MaxVal(void) {return ULONGLONG_MAX;} /***********************************************************************/ /* Set one value in a block from an array of characters. */ @@ -557,12 +573,36 @@ char *CHRBLK::GetCharValue(int n) return (char *)GetValPtrEx(n); } // end of GetCharValue +/***********************************************************************/ +/* Return the value of the nth element converted to tiny int. */ +/***********************************************************************/ +char CHRBLK::GetTinyValue(int n) + { + bool m; + ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX8, + false, &m); + + return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val; + } // end of GetTinyValue + +/***********************************************************************/ +/* Return the value of the nth element converted to unsigned tiny int.*/ +/***********************************************************************/ +uchar CHRBLK::GetUTinyValue(int n) + { + return (uchar)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX8, true); + } // end of GetTinyValue + /***********************************************************************/ /* Return the value of the nth element converted to short. */ /***********************************************************************/ short CHRBLK::GetShortValue(int n) { - return (short)atoi((char *)GetValPtrEx(n)); + bool m; + ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX16, + false, &m); + + return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val; } // end of GetShortValue /***********************************************************************/ @@ -570,7 +610,7 @@ short CHRBLK::GetShortValue(int n) /***********************************************************************/ ushort CHRBLK::GetUShortValue(int n) { - return (ushort)atoi((char *)GetValPtrEx(n)); + return (ushort)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX16, true); } // end of GetShortValue /***********************************************************************/ @@ -578,7 +618,11 @@ ushort CHRBLK::GetUShortValue(int n) /***********************************************************************/ int CHRBLK::GetIntValue(int n) { - return atol((char *)GetValPtrEx(n)); + bool m; + ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX32, + false, &m); + + return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val; } // end of GetIntValue /***********************************************************************/ @@ -586,7 +630,7 @@ int CHRBLK::GetIntValue(int n) /***********************************************************************/ uint CHRBLK::GetUIntValue(int n) { - return (unsigned)atol((char *)GetValPtrEx(n)); + return (uint)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX32, true); } // end of GetIntValue /***********************************************************************/ @@ -594,7 +638,11 @@ uint CHRBLK::GetUIntValue(int n) /***********************************************************************/ longlong CHRBLK::GetBigintValue(int n) { - return atoll((char *)GetValPtrEx(n)); + bool m; + ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX64, + false, &m); + + return (m && val < INT_MAX64) ? (longlong)(-(signed)val) : (longlong)val; } // end of GetBigintValue /***********************************************************************/ @@ -602,8 +650,8 @@ longlong CHRBLK::GetBigintValue(int n) /***********************************************************************/ ulonglong CHRBLK::GetUBigintValue(int n) { - return (unsigned)atoll((char *)GetValPtrEx(n)); - } // end of GetBigintValue + return CharToNumber((char*)GetValPtr(n), Long, ULONGLONG_MAX, true); + } // end of GetUBigintValue /***********************************************************************/ /* Return the value of the nth element converted to double. */ @@ -613,22 +661,6 @@ double CHRBLK::GetFloatValue(int n) return atof((char *)GetValPtrEx(n)); } // end of GetFloatValue -/***********************************************************************/ -/* Return the value of the nth element converted to tiny int. */ -/***********************************************************************/ -char CHRBLK::GetTinyValue(int n) - { - return (char)atoi((char *)GetValPtrEx(n)); - } // end of GetTinyValue - -/***********************************************************************/ -/* Return the value of the nth element converted to unsigned tiny int.*/ -/***********************************************************************/ -uchar CHRBLK::GetUTinyValue(int n) - { - return (uchar)atoi((char *)GetValPtrEx(n)); - } // end of GetTinyValue - /***********************************************************************/ /* Set one value in a block. */ /***********************************************************************/ @@ -869,6 +901,86 @@ void STRBLK::Init(PGLOBAL g, bool check) Global = g; } // end of Init +/***********************************************************************/ +/* Get the tiny value represented by the Strp string. */ +/***********************************************************************/ +char STRBLK::GetTinyValue(int n) + { + bool m; + ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX8, + false, &m); + + return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val; + } // end of GetTinyValue + +/***********************************************************************/ +/* Get the unsigned tiny value represented by the Strp string. */ +/***********************************************************************/ +uchar STRBLK::GetUTinyValue(int n) + { + return (uchar)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX8, true); + } // end of GetUTinyValue + +/***********************************************************************/ +/* Get the short value represented by the Strp string. */ +/***********************************************************************/ +short STRBLK::GetShortValue(int n) + { + bool m; + ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX16, + false, &m); + + return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val; + } // end of GetShortValue + +/***********************************************************************/ +/* Get the unsigned short value represented by the Strp string. */ +/***********************************************************************/ +ushort STRBLK::GetUShortValue(int n) + { + return (ushort)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX16, true); + } // end of GetUshortValue + +/***********************************************************************/ +/* Get the integer value represented by the Strp string. */ +/***********************************************************************/ +int STRBLK::GetIntValue(int n) + { + bool m; + ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX32, + false, &m); + + return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val; + } // end of GetIntValue + +/***********************************************************************/ +/* Get the unsigned integer value represented by the Strp string. */ +/***********************************************************************/ +uint STRBLK::GetUIntValue(int n) + { + return (uint)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX32, true); + } // end of GetUintValue + +/***********************************************************************/ +/* Get the big integer value represented by the Strp string. */ +/***********************************************************************/ +longlong STRBLK::GetBigintValue(int n) + { + bool m; + ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX64, + false, &m); + + return (m && val < INT_MAX64) ? (-(signed)val) : (longlong)val; + } // end of GetBigintValue + +/***********************************************************************/ +/* Get the unsigned big integer value represented by the Strp string. */ +/***********************************************************************/ +ulonglong STRBLK::GetUBigintValue(int n) + { + return CharToNumber(Strp[n], strlen(Strp[n]), ULONGLONG_MAX, true); + } // end of GetUBigintValue + /***********************************************************************/ /* Set one value in a block from a value in another block. */ /***********************************************************************/ diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h index fb3b0b7e72b..a3669cabd37 100644 --- a/storage/connect/valblk.h +++ b/storage/connect/valblk.h @@ -45,9 +45,12 @@ class VALBLK : public BLOCK { {if (To_Nulls) {To_Nulls[n] = (b) ? '*' : 0;}} virtual bool IsNull(int n) {return To_Nulls && To_Nulls[n];} virtual void SetNullable(bool b); + virtual bool IsUnsigned(void) {return Unsigned;} virtual void Init(PGLOBAL g, bool check) = 0; virtual int GetVlen(void) = 0; virtual PSZ GetCharValue(int n); + virtual char GetTinyValue(int n) = 0; + virtual uchar GetUTinyValue(int n) = 0; virtual short GetShortValue(int n) = 0; virtual ushort GetUShortValue(int n) = 0; virtual int GetIntValue(int n) = 0; @@ -55,8 +58,6 @@ class VALBLK : public BLOCK { virtual longlong GetBigintValue(int n) = 0; virtual ulonglong GetUBigintValue(int n) = 0; virtual double GetFloatValue(int n) = 0; - virtual char GetTinyValue(int n) = 0; - virtual uchar GetUTinyValue(int n) = 0; virtual void ReAlloc(void *mp, int n) {Blkp = mp; Nval = n;} virtual void Reset(int n) = 0; virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0); @@ -123,6 +124,8 @@ class TYPBLK : public VALBLK { virtual void Init(PGLOBAL g, bool check); virtual int GetVlen(void) {return sizeof(TYPE);} //virtual PSZ GetCharValue(int n); + virtual char GetTinyValue(int n) {return (char)Typp[n];} + virtual uchar GetUTinyValue(int n) {return (uchar)Typp[n];} virtual short GetShortValue(int n) {return (short)Typp[n];} virtual ushort GetUShortValue(int n) {return (ushort)Typp[n];} virtual int GetIntValue(int n) {return (int)Typp[n];} @@ -130,8 +133,6 @@ class TYPBLK : public VALBLK { virtual longlong GetBigintValue(int n) {return (longlong)Typp[n];} virtual ulonglong GetUBigintValue(int n) {return (ulonglong)Typp[n];} virtual double GetFloatValue(int n) {return (double)Typp[n];} - virtual char GetTinyValue(int n) {return (char)Typp[n];} - virtual uchar GetUTinyValue(int n) {return (uchar)Typp[n];} virtual void Reset(int n) {Typp[n] = 0;} // Methods @@ -168,9 +169,9 @@ class TYPBLK : public VALBLK { protected: // Specialized functions + static ulonglong MaxVal(void); TYPE GetTypedValue(PVAL vp); TYPE GetTypedValue(PVBLK blk, int n); - TYPE GetTypedValue(PSZ s); // Members TYPE* const &Typp; @@ -189,6 +190,8 @@ class CHRBLK : public VALBLK { virtual void Init(PGLOBAL g, bool check); virtual int GetVlen(void) {return Long;} virtual PSZ GetCharValue(int n); + virtual char GetTinyValue(int n); + virtual uchar GetUTinyValue(int n); virtual short GetShortValue(int n); virtual ushort GetUShortValue(int n); virtual int GetIntValue(int n); @@ -196,8 +199,6 @@ class CHRBLK : public VALBLK { virtual longlong GetBigintValue(int n); virtual ulonglong GetUBigintValue(int n); virtual double GetFloatValue(int n); - virtual char GetTinyValue(int n); - virtual uchar GetUTinyValue(int n); virtual void Reset(int n); virtual void SetPrec(int p) {Ci = (p != 0);} virtual bool IsCi(void) {return Ci;} @@ -242,15 +243,15 @@ class STRBLK : public VALBLK { virtual void Init(PGLOBAL g, bool check); virtual int GetVlen(void) {return sizeof(PSZ);} virtual PSZ GetCharValue(int n) {return Strp[n];} - virtual short GetShortValue(int n) {return (short)atoi(Strp[n]);} - virtual ushort GetUShortValue(int n) {return (ushort)atoi(Strp[n]);} - virtual int GetIntValue(int n) {return atol(Strp[n]);} - virtual uint GetUIntValue(int n) {return (unsigned)atol(Strp[n]);} - virtual longlong GetBigintValue(int n) {return atoll(Strp[n]);} - virtual ulonglong GetUBigintValue(int n) {return (unsigned)atoll(Strp[n]);} + virtual char GetTinyValue(int n); + virtual uchar GetUTinyValue(int n); + virtual short GetShortValue(int n); + virtual ushort GetUShortValue(int n); + virtual int GetIntValue(int n); + virtual uint GetUIntValue(int n); + virtual longlong GetBigintValue(int n); + virtual ulonglong GetUBigintValue(int n); virtual double GetFloatValue(int n) {return atof(Strp[n]);} - virtual char GetTinyValue(int n) {return (char)atoi(Strp[n]);} - virtual uchar GetUTinyValue(int n) {return (uchar)atoi(Strp[n]);} virtual void Reset(int n) {Strp[n] = NULL;} // Methods diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 077df346459..b41fafe6ecb 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -1,1776 +1,1866 @@ -/************* Value C++ Functions Source Code File (.CPP) *************/ -/* Name: VALUE.CPP Version 2.3 */ -/* */ -/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */ -/* */ -/* This file contains the VALUE and derived classes family functions. */ -/* These classes contain values of different types. They are used so */ -/* new object types can be defined and added to the processing simply */ -/* (hopefully) adding their specific functions in this file. */ -/* First family is VALUE that represent single typed objects. It is */ -/* used by columns (COLBLK), SELECT and FILTER (derived) objects. */ -/* Second family is VALBLK, representing simple suballocated arrays */ -/* of values treated sequentially by FIX, BIN and VCT tables and */ -/* columns, as well for min/max blocks as for VCT column blocks. */ -/* Q&A: why not using only one family ? Simple values are arrays that */ -/* have only one element and arrays could have functions for all kind */ -/* of processing. The answer is a-because historically it was simpler */ -/* to do that way, b-because of performance on single values, and c- */ -/* to avoid too complicated classes and unuseful duplication of many */ -/* functions used on one family only. The drawback is that for new */ -/* types of objects, we shall have more classes to update. */ -/* Currently the only implemented types are STRING, INT, SHORT, TINY, */ -/* DATE and LONGLONG. Recently we added some UNSIGNED types. */ -/***********************************************************************/ - -/***********************************************************************/ -/* Include relevant MariaDB header file. */ -/***********************************************************************/ -#include "my_global.h" -#include "sql_class.h" -#include "sql_time.h" - -#if defined(WIN32) -//#include -#else // !WIN32 -#include -#endif // !WIN32 - -#include - -#undef DOMAIN // Was defined in math.h - -/***********************************************************************/ -/* Include required application header files */ -/* global.h is header containing all global Plug declarations. */ -/* plgdbsem.h is header containing the DB applic. declarations. */ -/***********************************************************************/ -#include "global.h" -#include "plgdbsem.h" -#include "preparse.h" // For DATPAR -//#include "value.h" -#include "valblk.h" -#define NO_FUNC // Already defined in ODBConn -#include "plgcnx.h" // For DB types -#include "osutil.h" - -/***********************************************************************/ -/* Check macro's. */ -/***********************************************************************/ -#if defined(_DEBUG) -#define CheckType(V) if (Type != V->GetType()) { \ - PGLOBAL& g = Global; \ - strcpy(g->Message, MSG(VALTYPE_NOMATCH)); \ - longjmp(g->jumper[g->jump_level], Type); } -#else -#define CheckType(V) -#endif - -#define FOURYEARS 126230400 // Four years in seconds (1 leap) - -/***********************************************************************/ -/* Static variables. */ -/***********************************************************************/ -static char *list = - " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.*-abcdefghijklmnopqrstuv"; //wxyz' -//" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz."; -extern "C" int trace; - -/***********************************************************************/ -/* Initialize the DTVAL static member. */ -/***********************************************************************/ -int DTVAL::Shift = 0; - -/***********************************************************************/ -/* Routines called externally. */ -/***********************************************************************/ -bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool); -#if !defined(WIN32) -extern "C" { -PSZ strupr(PSZ s); -PSZ strlwr(PSZ s); -} -#endif // !WIN32 - -/***********************************************************************/ -/* GetTypeName: returns the PlugDB internal type name. */ -/***********************************************************************/ -PSZ GetTypeName(int type) - { - PSZ name; - - switch (type) { - case TYPE_STRING: name = "CHAR"; break; - case TYPE_SHORT: name = "SMALLINT"; break; - case TYPE_INT: name = "INTEGER"; break; - case TYPE_BIGINT: name = "BIGINT"; break; - case TYPE_DATE: name = "DATE"; break; - case TYPE_FLOAT: name = "FLOAT"; break; - case TYPE_TINY: name = "TINY"; break; - default: name = "UNKNOWN"; break; - } // endswitch type - - return name; - } // end of GetTypeName - -/***********************************************************************/ -/* GetTypeSize: returns the PlugDB internal type size. */ -/***********************************************************************/ -int GetTypeSize(int type, int len) - { - switch (type) { - case TYPE_STRING: len = len * sizeof(char); break; - case TYPE_SHORT: len = sizeof(short); break; - case TYPE_INT: len = sizeof(int); break; - case TYPE_BIGINT: len = sizeof(longlong); break; - case TYPE_DATE: len = sizeof(int); break; - case TYPE_FLOAT: len = sizeof(double); break; - case TYPE_TINY: len = sizeof(char); break; - default: len = 0; - } // endswitch type - - return len; - } // end of GetTypeSize - -/***********************************************************************/ -/* GetFormatType: returns the FORMAT character(s) according to type. */ -/***********************************************************************/ -char *GetFormatType(int type) - { - char *c = "X"; - - switch (type) { - case TYPE_STRING: c = "C"; break; - case TYPE_SHORT: c = "S"; break; - case TYPE_INT: c = "N"; break; - case TYPE_BIGINT: c = "L"; break; - case TYPE_FLOAT: c = "F"; break; - case TYPE_DATE: c = "D"; break; - case TYPE_TINY: c = "T"; break; - } // endswitch type - - return c; - } // end of GetFormatType - -/***********************************************************************/ -/* GetFormatType: returns the FORMAT type according to character. */ -/***********************************************************************/ -int GetFormatType(char c) - { - int type = TYPE_ERROR; - - switch (c) { - case 'C': type = TYPE_STRING; break; - case 'S': type = TYPE_SHORT; break; - case 'N': type = TYPE_INT; break; - case 'L': type = TYPE_BIGINT; break; - case 'F': type = TYPE_FLOAT; break; - case 'D': type = TYPE_DATE; break; - case 'T': type = TYPE_TINY; break; - } // endswitch type - - return type; - } // end of GetFormatType - - -/***********************************************************************/ -/* IsTypeChar: returns true for character type(s). */ -/***********************************************************************/ -bool IsTypeChar(int type) - { - switch (type) { - case TYPE_STRING: - return true; - } // endswitch type - - return false; - } // end of IsTypeChar - -/***********************************************************************/ -/* IsTypeNum: returns true for numeric types. */ -/***********************************************************************/ -bool IsTypeNum(int type) - { - switch (type) { - case TYPE_INT: - case TYPE_BIGINT: - case TYPE_DATE: - case TYPE_FLOAT: - case TYPE_SHORT: - case TYPE_NUM: - case TYPE_TINY: - return true; - } // endswitch type - - return false; - } // end of IsTypeNum - -/***********************************************************************/ -/* GetFmt: returns the format to use with a typed value. */ -/***********************************************************************/ -const char *GetFmt(int type, bool un) - { - const char *fmt; - - switch (type) { - case TYPE_STRING: fmt = "%s"; break; - case TYPE_SHORT: fmt = (un) ? "%hu" : "%hd"; break; - case TYPE_BIGINT: fmt = (un) ? "%llu" : "%lld"; break; - case TYPE_FLOAT: fmt = "%.*lf"; break; - default: fmt = (un) ? "%u" : "%d"; break; - } // endswitch Type - - return fmt; - } // end of GetFmt - -#if 0 -/***********************************************************************/ -/* ConvertType: what this function does is to determine the type to */ -/* which should be converted a value so no precision would be lost. */ -/* This can be a numeric type if num is true or non numeric if false. */ -/* Note: this is an ultra simplified version of this function that */ -/* should become more and more complex as new types are added. */ -/* Not evaluated types (TYPE_VOID or TYPE_UNDEF) return false from */ -/* IsType... functions so match does not prevent correct setting. */ -/***********************************************************************/ -int ConvertType(int target, int type, CONV kind, bool match) - { - switch (kind) { - case CNV_CHAR: - if (match && (!IsTypeChar(target) || !IsTypeChar(type))) - return TYPE_ERROR; - - return TYPE_STRING; - case CNV_NUM: - if (match && (!IsTypeNum(target) || !IsTypeNum(type))) - return TYPE_ERROR; - - return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT - : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE - : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT - : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT - : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT - : TYPE_TINY; - default: - if (target == TYPE_ERROR || target == type) - return type; - - if (match && ((IsTypeChar(target) && !IsTypeChar(type)) || - (IsTypeNum(target) && !IsTypeNum(type)))) - return TYPE_ERROR; - - return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT - : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE - : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT - : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT - : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT - : (target == TYPE_STRING || type == TYPE_STRING) ? TYPE_STRING - : (target == TYPE_TINY || type == TYPE_TINY) ? TYPE_TINY - : TYPE_ERROR; - } // endswitch kind - - } // end of ConvertType -#endif // 0 - -/***********************************************************************/ -/* AllocateConstant: allocates a constant Value. */ -/***********************************************************************/ -PVAL AllocateValue(PGLOBAL g, void *value, short type) - { - PVAL valp; - - if (trace) - htrc("AllocateConstant: value=%p type=%hd\n", value, type); - - switch (type) { - case TYPE_STRING: - valp = new(g) TYPVAL((PSZ)value); - break; - case TYPE_SHORT: - valp = new(g) TYPVAL(*(short*)value, TYPE_SHORT); - break; - case TYPE_INT: - valp = new(g) TYPVAL(*(int*)value, TYPE_INT); - break; - case TYPE_BIGINT: - valp = new(g) TYPVAL(*(longlong*)value, TYPE_BIGINT); - break; - case TYPE_FLOAT: - valp = new(g) TYPVAL(*(double *)value, TYPE_FLOAT, 2); - break; - case TYPE_TINY: - valp = new(g) TYPVAL(*(char *)value, TYPE_TINY); - break; - default: - sprintf(g->Message, MSG(BAD_VALUE_TYPE), type); - return NULL; - } // endswitch Type - - valp->SetGlobal(g); - return valp; - } // end of AllocateValue - -/***********************************************************************/ -/* Allocate a variable Value according to type, length and precision. */ -/***********************************************************************/ -PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, PSZ fmt) - { - PVAL valp; - - switch (type) { - case TYPE_STRING: - valp = new(g) TYPVAL(g, (PSZ)NULL, len, prec); - break; - case TYPE_DATE: - valp = new(g) DTVAL(g, len, prec, fmt); - break; - case TYPE_INT: - if (prec) - valp = new(g) TYPVAL((uint)0, TYPE_INT, 0, true); - else - valp = new(g) TYPVAL((int)0, TYPE_INT); - - break; - case TYPE_BIGINT: - if (prec) - valp = new(g) TYPVAL((ulonglong)0, TYPE_BIGINT, 0, true); - else - valp = new(g) TYPVAL((longlong)0, TYPE_BIGINT); - - break; - case TYPE_SHORT: - if (prec) - valp = new(g) TYPVAL((ushort)0, TYPE_SHORT, 0, true); - else - valp = new(g) TYPVAL((short)0, TYPE_SHORT); - - break; - case TYPE_FLOAT: - valp = new(g) TYPVAL(0.0, TYPE_FLOAT, prec); - break; - case TYPE_TINY: - if (prec) - valp = new(g) TYPVAL((uchar)0, TYPE_TINY, 0, true); - else - valp = new(g) TYPVAL((char)0, TYPE_TINY); - - break; - default: - sprintf(g->Message, MSG(BAD_VALUE_TYPE), type); - return NULL; - } // endswitch type - - valp->SetGlobal(g); - return valp; - } // end of AllocateValue - -/***********************************************************************/ -/* Allocate a constant Value converted to newtype. */ -/* Can also be used to copy a Value eventually converted. */ -/***********************************************************************/ -PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) - { - PSZ p, sp; - bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned(); - - if (newtype == TYPE_VOID) // Means allocate a value of the same type - newtype = valp->GetType(); - - switch (newtype) { - case TYPE_STRING: - p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen()); - - if ((sp = valp->GetCharString(p)) != p) - strcpy (p, sp); - - valp = new(g) TYPVAL(g, p, valp->GetValLen(), valp->GetValPrec()); - break; - case TYPE_SHORT: - if (un) - valp = new(g) TYPVAL(valp->GetUShortValue(), - TYPE_SHORT, 0, true); - else - valp = new(g) TYPVAL(valp->GetShortValue(), TYPE_SHORT); - - break; - case TYPE_INT: - if (un) - valp = new(g) TYPVAL(valp->GetUIntValue(), TYPE_INT, 0, true); - else - valp = new(g) TYPVAL(valp->GetIntValue(), TYPE_INT); - - break; - case TYPE_BIGINT: - if (un) - valp = new(g) TYPVAL(valp->GetUBigintValue(), - TYPE_BIGINT, 0, true); - else - valp = new(g) TYPVAL(valp->GetBigintValue(), TYPE_BIGINT); - - break; - case TYPE_DATE: - valp = new(g) DTVAL(g, valp->GetIntValue()); - break; - case TYPE_FLOAT: - valp = new(g) TYPVAL(valp->GetFloatValue(), TYPE_FLOAT, - valp->GetValPrec()); - break; - case TYPE_TINY: - if (un) - valp = new(g) TYPVAL(valp->GetUTinyValue(), - TYPE_TINY, 0, true); - else - valp = new(g) TYPVAL(valp->GetTinyValue(), TYPE_TINY); - - break; - default: - sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype); - return NULL; - } // endswitch type - - valp->SetGlobal(g); - return valp; - } // end of AllocateValue - - -/* -------------------------- Class VALUE ---------------------------- */ - -/***********************************************************************/ -/* Class VALUE protected constructor. */ -/***********************************************************************/ -VALUE::VALUE(int type, bool un) : Type(type) - { - Null = false; - Nullable = false; - Unsigned = un; - Clen = 0; - Prec = 0; - Fmt = GetFmt(Type, Unsigned); - Xfmt = GetXfmt(); - } // end of VALUE constructor - -/***********************************************************************/ -/* VALUE GetXfmt: returns the extended format to use with typed value. */ -/***********************************************************************/ -const char *VALUE::GetXfmt(void) - { - const char *fmt; - - switch (Type) { - case TYPE_STRING: fmt = "%*s"; break; - case TYPE_SHORT: fmt = (Unsigned) ? "%*hu" : "%*hd"; break; - case TYPE_BIGINT: fmt = (Unsigned) ? "%*llu" : "%*lld"; break; - case TYPE_FLOAT: fmt = "%*.*lf"; break; - default: fmt = (Unsigned) ? "%*u" : "%*d"; break; - } // endswitch Type - - return fmt; - } // end of GetFmt - -/* -------------------------- Class TYPVAL ---------------------------- */ - -/***********************************************************************/ -/* TYPVAL public constructor from a constant typed value. */ -/***********************************************************************/ -template -TYPVAL::TYPVAL(TYPE n, int type, int prec, bool un) - : VALUE(type, un) - { - Tval = n; - Clen = sizeof(TYPE); - Prec = prec; - } // end of TYPVAL constructor - -/***********************************************************************/ -/* TYPVAL GetValLen: returns the print length of the typed object. */ -/***********************************************************************/ -template -int TYPVAL::GetValLen(void) - { - char c[32]; - - return sprintf(c, Fmt, Tval); - } // end of GetValLen - -template <> -int TYPVAL::GetValLen(void) - { - char c[32]; - - return sprintf(c, Fmt, Prec, Tval); - } // end of GetValLen - -/***********************************************************************/ -/* TYPVAL SetValue: copy the value of another Value object. */ -/* This function allows conversion if chktype is false. */ -/***********************************************************************/ -template -bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) - { - if (chktype && Type != valp->GetType()) - return true; - - if (!(Null = valp->IsNull() && Nullable)) - Tval = GetTypedValue(valp); - else - Reset(); - - return false; - } // end of SetValue - -template <> -short TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetShortValue();} - -template <> -ushort TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetUShortValue();} - -template <> -int TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetIntValue();} - -template <> -uint TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetUIntValue();} - -template <> -longlong TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetBigintValue();} - -template <> -ulonglong TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetUBigintValue();} - -template <> -double TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetFloatValue();} - -template <> -char TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetTinyValue();} - -template <> -uchar TYPVAL::GetTypedValue(PVAL valp) - {return valp->GetUTinyValue();} - -/***********************************************************************/ -/* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/ -/***********************************************************************/ -template -void TYPVAL::SetValue_char(char *p, int n) - { - char *p2, buf[32]; - bool minus = false; - - for (p2 = p + n; p < p2 && *p == ' '; p++) ; - - for (Tval = 0, minus = false; p < p2; p++) - switch (*p) { - case '-': - minus = true; - case '+': - break; - case '0': Tval = Tval * 10; break; - case '1': Tval = Tval * 10 + 1; break; - case '2': Tval = Tval * 10 + 2; break; - case '3': Tval = Tval * 10 + 3; break; - case '4': Tval = Tval * 10 + 4; break; - case '5': Tval = Tval * 10 + 5; break; - case '6': Tval = Tval * 10 + 6; break; - case '7': Tval = Tval * 10 + 7; break; - case '8': Tval = Tval * 10 + 8; break; - case '9': Tval = Tval * 10 + 9; break; - default: - p = p2; - } // endswitch *p - - if (minus && Tval) - Tval = (-(signed)Tval) ? -(signed)Tval : Tval; - - if (trace > 1) - htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"), - GetTypeName(Type), Tval); - - Null = false; - } // end of SetValue - -template <> -void TYPVAL::SetValue_char(char *p, int n) - { - if (p) { - char buf[32]; - - for (; n > 0 && *p == ' '; p++) - n--; - - memcpy(buf, p, min(n, 31)); - buf[n] = '\0'; - Tval = atof(buf); - - if (trace > 1) - htrc(" setting double: '%s' -> %lf\n", buf, Tval); - - Null = false; - } else { - Reset(); - Null = Nullable; - } // endif p - - } // end of SetValue - -/***********************************************************************/ -/* TYPVAL SetValue: fill a typed value from a string. */ -/***********************************************************************/ -template -void TYPVAL::SetValue_psz(PSZ s) - { - if (s) { - Tval = GetTypedValue(s); - Null = false; - } else { - Reset(); - Null = Nullable; - } // endif p - - } // end of SetValue - -template <> -int TYPVAL::GetTypedValue(PSZ s) {return atol(s);} -template <> -uint TYPVAL::GetTypedValue(PSZ s) {return (unsigned)atol(s);} -template <> -short TYPVAL::GetTypedValue(PSZ s) {return (short)atoi(s);} -template <> -ushort TYPVAL::GetTypedValue(PSZ s) {return (ushort)atoi(s);} -template <> -longlong TYPVAL::GetTypedValue(PSZ s) {return atoll(s);} -template <> -ulonglong TYPVAL::GetTypedValue(PSZ s) {return (unsigned)atoll(s);} -template <> -double TYPVAL::GetTypedValue(PSZ s) {return atof(s);} -template <> -char TYPVAL::GetTypedValue(PSZ s) {return (char)atoi(s);} -template <> -uchar TYPVAL::GetTypedValue(PSZ s) {return (uchar)atoi(s);} - -/***********************************************************************/ -/* TYPVAL SetValue: set value with a TYPE extracted from a block. */ -/***********************************************************************/ -template -void TYPVAL::SetValue_pvblk(PVBLK blk, int n) - { - Tval = GetTypedValue(blk, n); - Null = false; - } // end of SetValue - -template <> -int TYPVAL::GetTypedValue(PVBLK blk, int n) - {return blk->GetIntValue(n);} - -template <> -uint TYPVAL::GetTypedValue(PVBLK blk, int n) - {return (unsigned)blk->GetIntValue(n);} - -template <> -short TYPVAL::GetTypedValue(PVBLK blk, int n) - {return blk->GetShortValue(n);} - -template <> -ushort TYPVAL::GetTypedValue(PVBLK blk, int n) - {return (unsigned)blk->GetShortValue(n);} - -template <> -longlong TYPVAL::GetTypedValue(PVBLK blk, int n) - {return blk->GetBigintValue(n);} - -template <> -ulonglong TYPVAL::GetTypedValue(PVBLK blk, int n) - {return (unsigned)blk->GetBigintValue(n);} - -template <> -double TYPVAL::GetTypedValue(PVBLK blk, int n) - {return blk->GetFloatValue(n);} - -template <> -char TYPVAL::GetTypedValue(PVBLK blk, int n) - {return blk->GetTinyValue(n);} - -template <> -uchar TYPVAL::GetTypedValue(PVBLK blk, int n) - {return (unsigned)blk->GetTinyValue(n);} - -/***********************************************************************/ -/* TYPVAL SetBinValue: with bytes extracted from a line. */ -/***********************************************************************/ -template -void TYPVAL::SetBinValue(void *p) - { - Tval = *(TYPE *)p; - Null = false; - } // end of SetBinValue - -/***********************************************************************/ -/* GetBinValue: fill a buffer with the internal binary value. */ -/* This function checks whether the buffer length is enough and */ -/* returns true if not. Actual filling occurs only if go is true. */ -/* Currently used by WriteColumn of binary files. */ -/***********************************************************************/ -template -bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) - { - // Test on length was removed here until a variable in column give the - // real field length. For BIN files the field length logically cannot - // be different from the variable length because no conversion is done. - // Therefore this test is useless anyway. -//#if defined(_DEBUG) -// if (sizeof(TYPE) > buflen) -// return true; -//#endif - - if (go) - *(TYPE *)buf = Tval; - - Null = false; - return false; - } // end of GetBinValue - -/***********************************************************************/ -/* TYPVAL ShowValue: get string representation of a typed value. */ -/***********************************************************************/ -template -char *TYPVAL::ShowValue(char *buf, int len) - { - sprintf(buf, Xfmt, len, Tval); - return buf; - } // end of ShowValue - -template <> -char *TYPVAL::ShowValue(char *buf, int len) - { - // TODO: use snprintf to avoid possible overflow - sprintf(buf, Xfmt, len, Prec, Tval); - return buf; - } // end of ShowValue - -/***********************************************************************/ -/* TYPVAL GetCharString: get string representation of a typed value. */ -/***********************************************************************/ -template -char *TYPVAL::GetCharString(char *p) - { - sprintf(p, Fmt, Tval); - return p; - } // end of GetCharString - -template <> -char *TYPVAL::GetCharString(char *p) - { - sprintf(p, Fmt, Prec, Tval); - return p; - } // end of GetCharString - -#if 0 -/***********************************************************************/ -/* TYPVAL GetShortString: get short representation of a typed value. */ -/***********************************************************************/ -template -char *TYPVAL::GetShortString(char *p, int n) - { - sprintf(p, "%*hd", n, (short)Tval); - return p; - } // end of GetShortString - -/***********************************************************************/ -/* TYPVAL GetIntString: get int representation of a typed value. */ -/***********************************************************************/ -template -char *TYPVAL::GetIntString(char *p, int n) - { - sprintf(p, "%*d", n, (int)Tval); - return p; - } // end of GetIntString - -/***********************************************************************/ -/* TYPVAL GetBigintString: get big int representation of a TYPE value.*/ -/***********************************************************************/ -template -char *TYPVAL::GetBigintString(char *p, int n) - { - sprintf(p, "%*lld", n, (longlong)Tval); - return p; - } // end of GetBigintString - -/***********************************************************************/ -/* TYPVAL GetFloatString: get double representation of a typed value. */ -/***********************************************************************/ -template -char *TYPVAL::GetFloatString(char *p, int n, int prec) - { - sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Tval); - return p; - } // end of GetFloatString - -/***********************************************************************/ -/* TYPVAL GetTinyString: get char representation of a typed value. */ -/***********************************************************************/ -template -char *TYPVAL::GetTinyString(char *p, int n) - { - sprintf(p, "%*d", n, (int)(char)Tval); - return p; - } // end of GetIntString -#endif // 0 - -/***********************************************************************/ -/* TYPVAL compare value with another Value. */ -/***********************************************************************/ -template -bool TYPVAL::IsEqual(PVAL vp, bool chktype) - { - if (this == vp) - return true; - else if (chktype && Type != vp->GetType()) - return false; - else if (Null || vp->IsNull()) - return false; - else - return (Tval == GetTypedValue(vp)); - - } // end of IsEqual - -/***********************************************************************/ -/* FormatValue: This function set vp (a STRING value) to the string */ -/* constructed from its own value formated using the fmt format. */ -/* This function assumes that the format matches the value type. */ -/***********************************************************************/ -template -bool TYPVAL::FormatValue(PVAL vp, char *fmt) - { - char *buf = (char*)vp->GetTo_Val(); // Should be big enough - int n = sprintf(buf, fmt, Tval); - - return (n > vp->GetValLen()); - } // end of FormatValue - -/***********************************************************************/ -/* TYPVAL SetFormat function (used to set SELECT output format). */ -/***********************************************************************/ -template -bool TYPVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt) - { - char c[32]; - - fmt.Type[0] = *GetFormatType(Type); - fmt.Length = sprintf(c, Fmt, Tval); - fmt.Prec = Prec; - return false; - } // end of SetConstFormat - -/***********************************************************************/ -/* Make file output of a typed object. */ -/***********************************************************************/ -template -void TYPVAL::Print(PGLOBAL g, FILE *f, uint n) - { - char m[64], buf[12]; - - memset(m, ' ', n); /* Make margin string */ - m[n] = '\0'; - - if (Null) - fprintf(f, "%s\n", m); - else - fprintf(f, strcat(strcat(strcpy(buf, "%s"), Fmt), "\n"), m, Tval); - - } /* end of Print */ - -/***********************************************************************/ -/* Make string output of a int object. */ -/***********************************************************************/ -template -void TYPVAL::Print(PGLOBAL g, char *ps, uint z) - { - if (Null) - strcpy(ps, ""); - else - sprintf(ps, Fmt, Tval); - - } /* end of Print */ - -/* -------------------------- Class STRING --------------------------- */ - -/***********************************************************************/ -/* STRING public constructor from a constant string. */ -/***********************************************************************/ -TYPVAL::TYPVAL(PSZ s) : VALUE(TYPE_STRING) - { - Strp = s; - Len = strlen(s); - Clen = Len; - Ci = false; - } // end of STRING constructor - -/***********************************************************************/ -/* STRING public constructor from char. */ -/***********************************************************************/ -TYPVAL::TYPVAL(PGLOBAL g, PSZ s, int n, int c) - : VALUE(TYPE_STRING) - { - Len = (g) ? n : strlen(s); - - if (!s) { - if (g) { - Strp = (char *)PlugSubAlloc(g, NULL, Len + 1); - Strp[Len] = '\0'; - } else - assert(false); - - } else - Strp = s; - - Clen = Len; - Ci = (c != 0); - } // end of STRING constructor - -/***********************************************************************/ -/* STRING SetValue: copy the value of another Value object. */ -/***********************************************************************/ -bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) - { - if (chktype && (valp->GetType() != Type || valp->GetSize() > Len)) - return true; - - char buf[32]; - - if (!(Null = valp->IsNull() && Nullable)) - strncpy(Strp, valp->GetCharString(buf), Len); - else - Reset(); - - return false; - } // end of SetValue_pval - -/***********************************************************************/ -/* STRING SetValue: fill string with chars extracted from a line. */ -/***********************************************************************/ -void TYPVAL::SetValue_char(char *p, int n) - { - if (p) { - if ((n = min(n, Len))) { - strncpy(Strp, p, n); - -// for (p = Strp + n - 1; p >= Strp && (*p == ' ' || *p == '\0'); p--) ; - for (p = Strp + n - 1; p >= Strp; p--) - if (*p && *p != ' ') - break; - - *(++p) = '\0'; - - if (trace > 1) - htrc(" Setting string to: '%s'\n", Strp); - - } else - Reset(); - - Null = false; - } else { - Reset(); - Null = Nullable; - } // endif p - - } // end of SetValue_char - -/***********************************************************************/ -/* STRING SetValue: fill string with another string. */ -/***********************************************************************/ -void TYPVAL::SetValue_psz(PSZ s) - { - if (s) { - strncpy(Strp, s, Len); - Null = false; - } else { - Reset(); - Null = Nullable; - } // endif s - - } // end of SetValue_psz - -/***********************************************************************/ -/* STRING SetValue: fill string with a string extracted from a block. */ -/***********************************************************************/ -void TYPVAL::SetValue_pvblk(PVBLK blk, int n) - { - strncpy(Strp, blk->GetCharValue(n), Len); - } // end of SetValue_pvblk - -/***********************************************************************/ -/* STRING SetValue: get the character representation of an integer. */ -/***********************************************************************/ -void TYPVAL::SetValue(int n) - { - char buf[16]; - PGLOBAL& g = Global; - int k = sprintf(buf, "%d", n); - - if (k > Len) { - sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); - longjmp(g->jumper[g->jump_level], 138); - } else - SetValue_psz(buf); - - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of an uint. */ -/***********************************************************************/ -void TYPVAL::SetValue(uint n) - { - char buf[16]; - PGLOBAL& g = Global; - int k = sprintf(buf, "%u", n); - - if (k > Len) { - sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); - longjmp(g->jumper[g->jump_level], 138); - } else - SetValue_psz(buf); - - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of a short int. */ -/***********************************************************************/ -void TYPVAL::SetValue(short i) - { - SetValue((int)i); - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of a ushort int. */ -/***********************************************************************/ -void TYPVAL::SetValue(ushort i) - { - SetValue((uint)i); - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of a big integer.*/ -/***********************************************************************/ -void TYPVAL::SetValue(longlong n) - { - char buf[24]; - PGLOBAL& g = Global; - int k = sprintf(buf, "%lld", n); - - if (k > Len) { - sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); - longjmp(g->jumper[g->jump_level], 138); - } else - SetValue_psz(buf); - - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of a big integer.*/ -/***********************************************************************/ -void TYPVAL::SetValue(ulonglong n) - { - char buf[24]; - PGLOBAL& g = Global; - int k = sprintf(buf, "%llu", n); - - if (k > Len) { - sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); - longjmp(g->jumper[g->jump_level], 138); - } else - SetValue_psz(buf); - - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of a double. */ -/***********************************************************************/ -void TYPVAL::SetValue(double f) - { - char *p, buf[32]; - PGLOBAL& g = Global; - int k = sprintf(buf, "%lf", f); - - for (p = buf + k - 1; p >= buf; p--) - if (*p == '0') { - *p = 0; - k--; - } else - break; - - if (k > Len) { - sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); - longjmp(g->jumper[g->jump_level], 138); - } else - SetValue_psz(buf); - - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of a tiny int. */ -/***********************************************************************/ -void TYPVAL::SetValue(char c) - { - SetValue((int)c); - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetValue: get the character representation of a tiny int. */ -/***********************************************************************/ -void TYPVAL::SetValue(uchar c) - { - SetValue((uint)c); - Null = false; - } // end of SetValue - -/***********************************************************************/ -/* STRING SetBinValue: fill string with chars extracted from a line. */ -/***********************************************************************/ -void TYPVAL::SetBinValue(void *p) - { - SetValue_char((char *)p, Len); - } // end of SetBinValue - -/***********************************************************************/ -/* GetBinValue: fill a buffer with the internal binary value. */ -/* This function checks whether the buffer length is enough and */ -/* returns true if not. Actual filling occurs only if go is true. */ -/* Currently used by WriteColumn of binary files. */ -/***********************************************************************/ -bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) - { - int len = (Null) ? 0 : strlen(Strp); - - if (len > buflen) - return true; - else if (go) { - memset(buf, ' ', buflen); - memcpy(buf, Strp, len); - } // endif go - - return false; - } // end of GetBinValue - -/***********************************************************************/ -/* STRING ShowValue: get string representation of a char value. */ -/***********************************************************************/ -char *TYPVAL::ShowValue(char *buf, int len) - { - return Strp; - } // end of ShowValue - -/***********************************************************************/ -/* STRING GetCharString: get string representation of a char value. */ -/***********************************************************************/ -char *TYPVAL::GetCharString(char *p) - { - return Strp; - } // end of GetCharString - -#if 0 -/***********************************************************************/ -/* STRING GetShortString: get short representation of a char value. */ -/***********************************************************************/ -char *TYPVAL::GetShortString(char *p, int n) - { - sprintf(p, "%*hd", n, (short)(Null ? 0 : atoi(Strp))); - return p; - } // end of GetShortString - -/***********************************************************************/ -/* STRING GetIntString: get int representation of a char value. */ -/***********************************************************************/ -char *TYPVAL::GetIntString(char *p, int n) - { - sprintf(p, "%*ld", n, (Null) ? 0 : atol(Strp)); - return p; - } // end of GetIntString - -/***********************************************************************/ -/* STRING GetBigintString: get big int representation of a char value.*/ -/***********************************************************************/ -char *TYPVAL::GetBigintString(char *p, int n) - { - sprintf(p, "%*lld", n, (Null) ? 0 : atoll(Strp)); - return p; - } // end of GetBigintString - -/***********************************************************************/ -/* STRING GetFloatString: get double representation of a char value. */ -/***********************************************************************/ -char *TYPVAL::GetFloatString(char *p, int n, int prec) - { - sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, Null ? 0 : atof(Strp)); - return p; - } // end of GetFloatString - -/***********************************************************************/ -/* STRING GetTinyString: get tiny int representation of a char value. */ -/***********************************************************************/ -char *TYPVAL::GetTinyString(char *p, int n) - { - sprintf(p, "%*d", n, (Null) ? 0 : (char)atoi(Strp)); - return p; - } // end of GetIntString -#endif // 0 - -/***********************************************************************/ -/* STRING compare value with another Value. */ -/***********************************************************************/ -bool TYPVAL::IsEqual(PVAL vp, bool chktype) - { - if (this == vp) - return true; - else if (chktype && Type != vp->GetType()) - return false; - else if (Null || vp->IsNull()) - return false; - - char buf[32]; - - if (Ci || vp->IsCi()) - return !stricmp(Strp, vp->GetCharString(buf)); - else // (!Ci) - return !strcmp(Strp, vp->GetCharString(buf)); - - } // end of IsEqual - -/***********************************************************************/ -/* FormatValue: This function set vp (a STRING value) to the string */ -/* constructed from its own value formated using the fmt format. */ -/* This function assumes that the format matches the value type. */ -/***********************************************************************/ -bool TYPVAL::FormatValue(PVAL vp, char *fmt) - { - char *buf = (char*)vp->GetTo_Val(); // Should be big enough - int n = sprintf(buf, fmt, Strp); - - return (n > vp->GetValLen()); - } // end of FormatValue - -/***********************************************************************/ -/* STRING SetFormat function (used to set SELECT output format). */ -/***********************************************************************/ -bool TYPVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt) - { - fmt.Type[0] = 'C'; - fmt.Length = Len; - fmt.Prec = 0; - return false; - } // end of SetConstFormat - -/* -------------------------- Class DTVAL ---------------------------- */ - -/***********************************************************************/ -/* DTVAL public constructor for new void values. */ -/***********************************************************************/ -DTVAL::DTVAL(PGLOBAL g, int n, int prec, PSZ fmt) - : TYPVAL((int)0, TYPE_DATE) - { - if (!fmt) { - Pdtp = NULL; - Sdate = NULL; - DefYear = 0; - Len = n; - } else - SetFormat(g, fmt, n, prec); - -//Type = TYPE_DATE; - } // end of DTVAL constructor - -/***********************************************************************/ -/* DTVAL public constructor from int. */ -/***********************************************************************/ -DTVAL::DTVAL(PGLOBAL g, int n) : TYPVAL(n, TYPE_DATE) - { - Pdtp = NULL; - Len = 19; -//Type = TYPE_DATE; - Sdate = NULL; - DefYear = 0; - } // end of DTVAL constructor - -/***********************************************************************/ -/* Set format so formatted dates can be converted on input/output. */ -/***********************************************************************/ -bool DTVAL::SetFormat(PGLOBAL g, PSZ fmt, int len, int year) - { - Pdtp = MakeDateFormat(g, fmt, true, true, (year > 9999) ? 1 : 0); - Sdate = (char*)PlugSubAlloc(g, NULL, len + 1); - DefYear = (int)((year > 9999) ? (year - 10000) : year); - Len = len; - return false; - } // end of SetFormat - -/***********************************************************************/ -/* Set format from the format of another date value. */ -/***********************************************************************/ -bool DTVAL::SetFormat(PGLOBAL g, PVAL valp) - { - DTVAL *vp; - - if (valp->GetType() != TYPE_DATE) { - sprintf(g->Message, MSG(NO_FORMAT_TYPE), valp->GetType()); - return true; - } else - vp = (DTVAL*)valp; - - Len = vp->Len; - Pdtp = vp->Pdtp; - Sdate = (char*)PlugSubAlloc(g, NULL, Len + 1); - DefYear = vp->DefYear; - return false; - } // end of SetFormat - -/***********************************************************************/ -/* We need TimeShift because the mktime C function does a correction */ -/* for local time zone that we want to override for DB operations. */ -/***********************************************************************/ -void DTVAL::SetTimeShift(void) - { - struct tm dtm; - memset(&dtm, 0, sizeof(dtm)); - dtm.tm_mday=2; - dtm.tm_mon=0; - dtm.tm_year=70; - - Shift = (int)mktime(&dtm) - 86400; - - if (trace) - htrc("DTVAL Shift=%d\n", Shift); - - } // end of SetTimeShift - -/***********************************************************************/ -/* GetGmTime: returns a pointer to a static tm structure obtained */ -/* though the gmtime C function. The purpose of this function is to */ -/* extend the range of valid dates by accepting negative time values. */ -/***********************************************************************/ -static void TIME_to_localtime(struct tm *tm, const MYSQL_TIME *ltime) -{ - bzero(tm, sizeof(*tm)); - tm->tm_year= ltime->year - 1900; - tm->tm_mon= ltime->month - 1; - tm->tm_mday= ltime->day; - tm->tm_hour= ltime->hour; - tm->tm_min= ltime->minute; - tm->tm_sec= ltime->second; -} - - -static struct tm *gmtime_mysql(const time_t *timep, struct tm *tm) -{ - MYSQL_TIME ltime; - thd_gmt_sec_to_TIME(current_thd, <ime, (my_time_t) *timep); - TIME_to_localtime(tm, <ime); - return tm; -} - - -struct tm *DTVAL::GetGmTime(struct tm *tm_buffer) - { - struct tm *datm; - time_t t = (time_t)Tval; - - if (Tval < 0) { - int n; - - for (n = 0; t < 0; n += 4) - t += FOURYEARS; - - datm = gmtime_mysql(&t, tm_buffer); - - if (datm) - datm->tm_year -= n; - - } else - datm = gmtime_mysql(&t, tm_buffer); - - return datm; - } // end of GetGmTime - -/***********************************************************************/ -/* MakeTime: calculates a date value from a tm structures using the */ -/* mktime C function. The purpose of this function is to extend the */ -/* range of valid dates by accepting to set negative time values. */ -/***********************************************************************/ - -static time_t mktime_mysql(struct tm *ptm) -{ - MYSQL_TIME ltime; - localtime_to_TIME(<ime, ptm); - ltime.time_type= MYSQL_TIMESTAMP_DATETIME; - uint error_code; - time_t t= TIME_to_timestamp(current_thd, <ime, &error_code); - return error_code ? (time_t) -1 : t; -} - -bool DTVAL::MakeTime(struct tm *ptm) - { - int n, y = ptm->tm_year; - time_t t = mktime_mysql(ptm); - - if (trace > 1) - htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n", - ptm->tm_year, ptm->tm_mon, ptm->tm_mday, - ptm->tm_hour, ptm->tm_min, ptm->tm_sec); - - if (t == -1) { - if (y < 1 || y > 71) - return true; - - for (n = 0; t == -1 && n < 20; n++) { - ptm->tm_year += 4; - t = mktime_mysql(ptm); - } // endfor t - - if (t == -1) - return true; - - if ((t -= (n * FOURYEARS)) > 2000000000) - return true; - - } - Tval= (int) t; - - if (trace > 1) - htrc("MakeTime Ival=%d\n", Tval); - - return false; - } // end of MakeTime - -/***********************************************************************/ -/* Make a time_t datetime from its components (YY, MM, DD, hh, mm, ss) */ -/***********************************************************************/ -bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) - { - int i, m; - int n; - bool rc = false; - struct tm datm; - bzero(&datm, sizeof(datm)); - datm.tm_mday=1; - datm.tm_mon=0; - datm.tm_year=70; - - if (trace > 1) - htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n", - val[0], val[1], val[2], val[3], val[4], val[5], nval); - - for (i = 0; i < nval; i++) { - n = val[i]; - -// if (trace > 1) -// htrc("i=%d n=%d\n", i, n); - - switch (i) { - case 0: - if (n >= 1900) - n -= 1900; - - datm.tm_year = n; - -// if (trace > 1) -// htrc("n=%d tm_year=%d\n", n, datm.tm_year); - - break; - case 1: - // If mktime handles apparently correctly large or negative - // day values, it is not the same for months. Therefore we - // do the ajustment here, thus mktime has not to do it. - if (n > 0) { - m = (n - 1) % 12; - n = (n - 1) / 12; - } else { - m = 11 + n % 12; - n = n / 12 - 1; - } // endfi n - - datm.tm_mon = m; - datm.tm_year += n; - -// if (trace > 1) -// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon); - - break; - case 2: - // For days, big or negative values may also cause problems - m = n % 1461; - n = 4 * (n / 1461); - - if (m < 0) { - m += 1461; - n -= 4; - } // endif m - - datm.tm_mday = m; - datm.tm_year += n; - -// if (trace > 1) -// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon); - - break; - case 3: datm.tm_hour = n; break; - case 4: datm.tm_min = n; break; - case 5: datm.tm_sec = n; break; - } // endswitch i - - } // endfor i - - if (trace > 1) - htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n", - datm.tm_year, datm.tm_mon, datm.tm_mday, - datm.tm_hour, datm.tm_min, datm.tm_sec); - - // Pass g to have an error return or NULL to set invalid dates to 0 - if (MakeTime(&datm)) - if (g) { - strcpy(g->Message, MSG(BAD_DATETIME)); - rc = true; - } else - Tval = 0; - - return rc; - } // end of MakeDate - -/***********************************************************************/ -/* DTVAL SetValue: copy the value of another Value object. */ -/* This function allows conversion if chktype is false. */ -/***********************************************************************/ -bool DTVAL::SetValue_pval(PVAL valp, bool chktype) - { - if (chktype && Type != valp->GetType()) - return true; - - if (!(Null = valp->IsNull() && Nullable)) { - if (Pdtp && !valp->IsTypeNum()) { - int ndv; - int dval[6]; - - ndv = ExtractDate(valp->GetCharValue(), Pdtp, DefYear, dval); - MakeDate(NULL, dval, ndv); - } else - Tval = valp->GetIntValue(); - - } else - Reset(); - - return false; - } // end of SetValue - -/***********************************************************************/ -/* SetValue: convert chars extracted from a line to date value. */ -/***********************************************************************/ -void DTVAL::SetValue_char(char *p, int n) - { - if (Pdtp) { - char *p2; - int ndv; - int dval[6]; - - // Trim trailing blanks - for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--) ; - - n = min(p2 - p + 1, Len); - memcpy(Sdate, p, n); - Sdate[n] = '\0'; - - ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); - MakeDate(NULL, dval, ndv); - - if (trace > 1) - htrc(" setting date: '%s' -> %d\n", Sdate, Tval); - - Null = false; - } else - TYPVAL::SetValue_char(p, n); - - } // end of SetValue - -/***********************************************************************/ -/* SetValue: convert a char string to date value. */ -/***********************************************************************/ -void DTVAL::SetValue_psz(PSZ p) - { - if (Pdtp) { - int ndv; - int dval[6]; - - strncpy(Sdate, p, Len); - Sdate[Len] = '\0'; - - ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); - MakeDate(NULL, dval, ndv); - - if (trace > 1) - htrc(" setting date: '%s' -> %d\n", Sdate, Tval); - - Null = false; - } else - TYPVAL::SetValue_psz(p); - - } // end of SetValue - -/***********************************************************************/ -/* DTVAL SetValue: set value with a value extracted from a block. */ -/***********************************************************************/ -void DTVAL::SetValue_pvblk(PVBLK blk, int n) - { - if (Pdtp && !::IsTypeNum(blk->GetType())) { - int ndv; - int dval[6]; - - ndv = ExtractDate(blk->GetCharValue(n), Pdtp, DefYear, dval); - MakeDate(NULL, dval, ndv); - } else - Tval = blk->GetIntValue(n); - - } // end of SetValue - -/***********************************************************************/ -/* DTVAL GetCharString: get string representation of a date value. */ -/***********************************************************************/ -char *DTVAL::GetCharString(char *p) - { - if (Pdtp) { - size_t n = 0; - struct tm tm, *ptm= GetGmTime(&tm); - - if (ptm) - n = strftime(Sdate, Len + 1, Pdtp->OutFmt, ptm); - - if (!n) { - *Sdate = '\0'; - strncat(Sdate, "Error", Len + 1); - } // endif n - - return Sdate; - } else - sprintf(p, "%d", Tval); - - Null = false; - return p; - } // end of GetCharString - -/***********************************************************************/ -/* DTVAL ShowValue: get string representation of a date value. */ -/***********************************************************************/ -char *DTVAL::ShowValue(char *buf, int len) - { - if (Pdtp) { - char *p; - size_t m, n = 0; - struct tm tm, *ptm = GetGmTime(&tm); - - if (Len < len) { - p = buf; - m = len; - } else { - p = Sdate; - m = Len + 1; - } // endif Len - - if (ptm) - n = strftime(p, m, Pdtp->OutFmt, ptm); - - if (!n) { - *p = '\0'; - strncat(p, "Error", m); - } // endif n - - return p; - } else - return TYPVAL::ShowValue(buf, len); - - } // end of ShowValue - -/***********************************************************************/ -/* Returns a member of the struct tm representation of the date. */ -/***********************************************************************/ -bool DTVAL::GetTmMember(OPVAL op, int& mval) - { - bool rc = false; - struct tm tm, *ptm = GetGmTime(&tm); - - switch (op) { - case OP_MDAY: mval = ptm->tm_mday; break; - case OP_MONTH: mval = ptm->tm_mon + 1; break; - case OP_YEAR: mval = ptm->tm_year + 1900; break; - case OP_WDAY: mval = ptm->tm_wday + 1; break; - case OP_YDAY: mval = ptm->tm_yday + 1; break; - case OP_QUART: mval = ptm->tm_mon / 3 + 1; break; - default: - rc = true; - } // endswitch op - - return rc; - } // end of GetTmMember - -/***********************************************************************/ -/* Calculates the week number of the year for the internal date value.*/ -/* The International Standard ISO 8601 has decreed that Monday shall */ -/* be the first day of the week. A week that lies partly in one year */ -/* and partly in another is assigned a number in the year in which */ -/* most of its days lie. That means that week number 1 of any year is */ -/* the week that contains the January 4th. */ -/***********************************************************************/ -bool DTVAL::WeekNum(PGLOBAL g, int& nval) - { - // w is the start of the week SUN=0, MON=1, etc. - int m, n, w = nval % 7; - struct tm tm, *ptm = GetGmTime(&tm); - - // Which day is January 4th of this year? - m = (367 + ptm->tm_wday - ptm->tm_yday) % 7; - - // When does the first week begins? - n = 3 - (7 + m - w) % 7; - - // Now calculate the week number - if (!(nval = (7 + ptm->tm_yday - n) / 7)) - nval = 52; - - // Everything should be Ok - return false; - } // end of WeekNum - -/***********************************************************************/ -/* FormatValue: This function set vp (a STRING value) to the string */ -/* constructed from its own value formated using the fmt format. */ -/* This function assumes that the format matches the value type. */ -/***********************************************************************/ -bool DTVAL::FormatValue(PVAL vp, char *fmt) - { - char *buf = (char*)vp->GetTo_Val(); // Should be big enough - struct tm tm, *ptm = GetGmTime(&tm); - - if (trace) - htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen()); - - if (ptm) { - size_t n = strftime(buf, vp->GetValLen(), fmt, ptm); - - if (trace) - htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???"); - - return (n == 0); - } else - return true; - - } // end of FormatValue - -/* -------------------------- End of Value --------------------------- */ +/************* Value C++ Functions Source Code File (.CPP) *************/ +/* Name: VALUE.CPP Version 2.3 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */ +/* */ +/* This file contains the VALUE and derived classes family functions. */ +/* These classes contain values of different types. They are used so */ +/* new object types can be defined and added to the processing simply */ +/* (hopefully) adding their specific functions in this file. */ +/* First family is VALUE that represent single typed objects. It is */ +/* used by columns (COLBLK), SELECT and FILTER (derived) objects. */ +/* Second family is VALBLK, representing simple suballocated arrays */ +/* of values treated sequentially by FIX, BIN and VCT tables and */ +/* columns, as well for min/max blocks as for VCT column blocks. */ +/* Q&A: why not using only one family ? Simple values are arrays that */ +/* have only one element and arrays could have functions for all kind */ +/* of processing. The answer is a-because historically it was simpler */ +/* to do that way, b-because of performance on single values, and c- */ +/* to avoid too complicated classes and unuseful duplication of many */ +/* functions used on one family only. The drawback is that for new */ +/* types of objects, we shall have more classes to update. */ +/* Currently the only implemented types are STRING, INT, SHORT, TINY, */ +/* DATE and LONGLONG. Recently we added some UNSIGNED types. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant MariaDB header file. */ +/***********************************************************************/ +#include "my_global.h" +#include "sql_class.h" +#include "sql_time.h" + +#if defined(WIN32) +//#include +#else // !WIN32 +#include +#endif // !WIN32 + +#include + +#undef DOMAIN // Was defined in math.h + +/***********************************************************************/ +/* Include required application header files */ +/* global.h is header containing all global Plug declarations. */ +/* plgdbsem.h is header containing the DB applic. declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "preparse.h" // For DATPAR +//#include "value.h" +#include "valblk.h" +#define NO_FUNC // Already defined in ODBConn +#include "plgcnx.h" // For DB types +#include "osutil.h" + +/***********************************************************************/ +/* Check macro's. */ +/***********************************************************************/ +#if defined(_DEBUG) +#define CheckType(V) if (Type != V->GetType()) { \ + PGLOBAL& g = Global; \ + strcpy(g->Message, MSG(VALTYPE_NOMATCH)); \ + longjmp(g->jumper[g->jump_level], Type); } +#else +#define CheckType(V) +#endif + +#define FOURYEARS 126230400 // Four years in seconds (1 leap) + +/***********************************************************************/ +/* Static variables. */ +/***********************************************************************/ +static char *list = + " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.*-abcdefghijklmnopqrstuv"; //wxyz' +//" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz."; +extern "C" int trace; + +/***********************************************************************/ +/* Initialize the DTVAL static member. */ +/***********************************************************************/ +int DTVAL::Shift = 0; + +/***********************************************************************/ +/* Routines called externally. */ +/***********************************************************************/ +bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool); +#if !defined(WIN32) +extern "C" { +PSZ strupr(PSZ s); +PSZ strlwr(PSZ s); +} +#endif // !WIN32 + +/***********************************************************************/ +/* Get a long long number from its character representation. */ +/* IN p: Pointer to the numeric string */ +/* IN n: The string length */ +/* IN maxval: The number max value */ +/* IN un: True if the number must be unsigned */ +/* OUT rc: Set to TRUE for out of range value */ +/* OUT minus: Set to true if the number is negative */ +/* Returned val: The resulting number */ +/***********************************************************************/ +ulonglong CharToNumber(char *p, int n, ulonglong maxval, + bool un, bool *minus, bool *rc) +{ + char *p2; + uchar c; + ulonglong val; + + if (minus) *minus = false; + if (rc) *rc = false; + + // Eliminate leading blanks or 0 + for (p2 = p + n; p < p2 && (*p == ' ' || *p == '0'); p++) ; + + // Get an eventual sign character + switch (*p) { + case '-': + if (un) { + if (rc) *rc = true; + return 0; + } else { + maxval++; + if (minus) *minus = true; + } // endif Unsigned + + case '+': + p++; + break; + } // endswitch *p + + for (val = 0; p < p2 && (c = (uchar)(*p - '0')) < 10; p++) + if (val > (maxval - c) / 10) { + val = maxval; + if (rc) *rc = true; + break; + } else + val = val * 10 + c; + + return val; +} // end of CharToNumber + +/***********************************************************************/ +/* GetTypeName: returns the PlugDB internal type name. */ +/***********************************************************************/ +PSZ GetTypeName(int type) + { + PSZ name; + + switch (type) { + case TYPE_STRING: name = "CHAR"; break; + case TYPE_SHORT: name = "SMALLINT"; break; + case TYPE_INT: name = "INTEGER"; break; + case TYPE_BIGINT: name = "BIGINT"; break; + case TYPE_DATE: name = "DATE"; break; + case TYPE_FLOAT: name = "FLOAT"; break; + case TYPE_TINY: name = "TINY"; break; + default: name = "UNKNOWN"; break; + } // endswitch type + + return name; + } // end of GetTypeName + +/***********************************************************************/ +/* GetTypeSize: returns the PlugDB internal type size. */ +/***********************************************************************/ +int GetTypeSize(int type, int len) + { + switch (type) { + case TYPE_STRING: len = len * sizeof(char); break; + case TYPE_SHORT: len = sizeof(short); break; + case TYPE_INT: len = sizeof(int); break; + case TYPE_BIGINT: len = sizeof(longlong); break; + case TYPE_DATE: len = sizeof(int); break; + case TYPE_FLOAT: len = sizeof(double); break; + case TYPE_TINY: len = sizeof(char); break; + default: len = 0; + } // endswitch type + + return len; + } // end of GetTypeSize + +/***********************************************************************/ +/* GetFormatType: returns the FORMAT character(s) according to type. */ +/***********************************************************************/ +char *GetFormatType(int type) + { + char *c = "X"; + + switch (type) { + case TYPE_STRING: c = "C"; break; + case TYPE_SHORT: c = "S"; break; + case TYPE_INT: c = "N"; break; + case TYPE_BIGINT: c = "L"; break; + case TYPE_FLOAT: c = "F"; break; + case TYPE_DATE: c = "D"; break; + case TYPE_TINY: c = "T"; break; + } // endswitch type + + return c; + } // end of GetFormatType + +/***********************************************************************/ +/* GetFormatType: returns the FORMAT type according to character. */ +/***********************************************************************/ +int GetFormatType(char c) + { + int type = TYPE_ERROR; + + switch (c) { + case 'C': type = TYPE_STRING; break; + case 'S': type = TYPE_SHORT; break; + case 'N': type = TYPE_INT; break; + case 'L': type = TYPE_BIGINT; break; + case 'F': type = TYPE_FLOAT; break; + case 'D': type = TYPE_DATE; break; + case 'T': type = TYPE_TINY; break; + } // endswitch type + + return type; + } // end of GetFormatType + + +/***********************************************************************/ +/* IsTypeChar: returns true for character type(s). */ +/***********************************************************************/ +bool IsTypeChar(int type) + { + switch (type) { + case TYPE_STRING: + return true; + } // endswitch type + + return false; + } // end of IsTypeChar + +/***********************************************************************/ +/* IsTypeNum: returns true for numeric types. */ +/***********************************************************************/ +bool IsTypeNum(int type) + { + switch (type) { + case TYPE_INT: + case TYPE_BIGINT: + case TYPE_DATE: + case TYPE_FLOAT: + case TYPE_SHORT: + case TYPE_NUM: + case TYPE_TINY: + return true; + } // endswitch type + + return false; + } // end of IsTypeNum + +/***********************************************************************/ +/* GetFmt: returns the format to use with a typed value. */ +/***********************************************************************/ +const char *GetFmt(int type, bool un) + { + const char *fmt; + + switch (type) { + case TYPE_STRING: fmt = "%s"; break; + case TYPE_SHORT: fmt = (un) ? "%hu" : "%hd"; break; + case TYPE_BIGINT: fmt = (un) ? "%llu" : "%lld"; break; + case TYPE_FLOAT: fmt = "%.*lf"; break; + default: fmt = (un) ? "%u" : "%d"; break; + } // endswitch Type + + return fmt; + } // end of GetFmt + +#if 0 +/***********************************************************************/ +/* ConvertType: what this function does is to determine the type to */ +/* which should be converted a value so no precision would be lost. */ +/* This can be a numeric type if num is true or non numeric if false. */ +/* Note: this is an ultra simplified version of this function that */ +/* should become more and more complex as new types are added. */ +/* Not evaluated types (TYPE_VOID or TYPE_UNDEF) return false from */ +/* IsType... functions so match does not prevent correct setting. */ +/***********************************************************************/ +int ConvertType(int target, int type, CONV kind, bool match) + { + switch (kind) { + case CNV_CHAR: + if (match && (!IsTypeChar(target) || !IsTypeChar(type))) + return TYPE_ERROR; + + return TYPE_STRING; + case CNV_NUM: + if (match && (!IsTypeNum(target) || !IsTypeNum(type))) + return TYPE_ERROR; + + return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT + : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE + : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT + : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT + : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT + : TYPE_TINY; + default: + if (target == TYPE_ERROR || target == type) + return type; + + if (match && ((IsTypeChar(target) && !IsTypeChar(type)) || + (IsTypeNum(target) && !IsTypeNum(type)))) + return TYPE_ERROR; + + return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT + : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE + : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT + : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT + : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT + : (target == TYPE_STRING || type == TYPE_STRING) ? TYPE_STRING + : (target == TYPE_TINY || type == TYPE_TINY) ? TYPE_TINY + : TYPE_ERROR; + } // endswitch kind + + } // end of ConvertType +#endif // 0 + +/***********************************************************************/ +/* AllocateConstant: allocates a constant Value. */ +/***********************************************************************/ +PVAL AllocateValue(PGLOBAL g, void *value, short type) + { + PVAL valp; + + if (trace) + htrc("AllocateConstant: value=%p type=%hd\n", value, type); + + switch (type) { + case TYPE_STRING: + valp = new(g) TYPVAL((PSZ)value); + break; + case TYPE_SHORT: + valp = new(g) TYPVAL(*(short*)value, TYPE_SHORT); + break; + case TYPE_INT: + valp = new(g) TYPVAL(*(int*)value, TYPE_INT); + break; + case TYPE_BIGINT: + valp = new(g) TYPVAL(*(longlong*)value, TYPE_BIGINT); + break; + case TYPE_FLOAT: + valp = new(g) TYPVAL(*(double *)value, TYPE_FLOAT, 2); + break; + case TYPE_TINY: + valp = new(g) TYPVAL(*(char *)value, TYPE_TINY); + break; + default: + sprintf(g->Message, MSG(BAD_VALUE_TYPE), type); + return NULL; + } // endswitch Type + + valp->SetGlobal(g); + return valp; + } // end of AllocateValue + +/***********************************************************************/ +/* Allocate a variable Value according to type, length and precision. */ +/***********************************************************************/ +PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, PSZ fmt) + { + PVAL valp; + + switch (type) { + case TYPE_STRING: + valp = new(g) TYPVAL(g, (PSZ)NULL, len, prec); + break; + case TYPE_DATE: + valp = new(g) DTVAL(g, len, prec, fmt); + break; + case TYPE_INT: + if (prec) + valp = new(g) TYPVAL((uint)0, TYPE_INT, 0, true); + else + valp = new(g) TYPVAL((int)0, TYPE_INT); + + break; + case TYPE_BIGINT: + if (prec) + valp = new(g) TYPVAL((ulonglong)0, TYPE_BIGINT, 0, true); + else + valp = new(g) TYPVAL((longlong)0, TYPE_BIGINT); + + break; + case TYPE_SHORT: + if (prec) + valp = new(g) TYPVAL((ushort)0, TYPE_SHORT, 0, true); + else + valp = new(g) TYPVAL((short)0, TYPE_SHORT); + + break; + case TYPE_FLOAT: + valp = new(g) TYPVAL(0.0, TYPE_FLOAT, prec); + break; + case TYPE_TINY: + if (prec) + valp = new(g) TYPVAL((uchar)0, TYPE_TINY, 0, true); + else + valp = new(g) TYPVAL((char)0, TYPE_TINY); + + break; + default: + sprintf(g->Message, MSG(BAD_VALUE_TYPE), type); + return NULL; + } // endswitch type + + valp->SetGlobal(g); + return valp; + } // end of AllocateValue + +/***********************************************************************/ +/* Allocate a constant Value converted to newtype. */ +/* Can also be used to copy a Value eventually converted. */ +/***********************************************************************/ +PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) + { + PSZ p, sp; + bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned(); + + if (newtype == TYPE_VOID) // Means allocate a value of the same type + newtype = valp->GetType(); + + switch (newtype) { + case TYPE_STRING: + p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen()); + + if ((sp = valp->GetCharString(p)) != p) + strcpy (p, sp); + + valp = new(g) TYPVAL(g, p, valp->GetValLen(), valp->GetValPrec()); + break; + case TYPE_SHORT: + if (un) + valp = new(g) TYPVAL(valp->GetUShortValue(), + TYPE_SHORT, 0, true); + else + valp = new(g) TYPVAL(valp->GetShortValue(), TYPE_SHORT); + + break; + case TYPE_INT: + if (un) + valp = new(g) TYPVAL(valp->GetUIntValue(), TYPE_INT, 0, true); + else + valp = new(g) TYPVAL(valp->GetIntValue(), TYPE_INT); + + break; + case TYPE_BIGINT: + if (un) + valp = new(g) TYPVAL(valp->GetUBigintValue(), + TYPE_BIGINT, 0, true); + else + valp = new(g) TYPVAL(valp->GetBigintValue(), TYPE_BIGINT); + + break; + case TYPE_DATE: + valp = new(g) DTVAL(g, valp->GetIntValue()); + break; + case TYPE_FLOAT: + valp = new(g) TYPVAL(valp->GetFloatValue(), TYPE_FLOAT, + valp->GetValPrec()); + break; + case TYPE_TINY: + if (un) + valp = new(g) TYPVAL(valp->GetUTinyValue(), + TYPE_TINY, 0, true); + else + valp = new(g) TYPVAL(valp->GetTinyValue(), TYPE_TINY); + + break; + default: + sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype); + return NULL; + } // endswitch type + + valp->SetGlobal(g); + return valp; + } // end of AllocateValue + + +/* -------------------------- Class VALUE ---------------------------- */ + +/***********************************************************************/ +/* Class VALUE protected constructor. */ +/***********************************************************************/ +VALUE::VALUE(int type, bool un) : Type(type) + { + Null = false; + Nullable = false; + Unsigned = un; + Clen = 0; + Prec = 0; + Fmt = GetFmt(Type, Unsigned); + Xfmt = GetXfmt(); + } // end of VALUE constructor + +/***********************************************************************/ +/* VALUE GetXfmt: returns the extended format to use with typed value. */ +/***********************************************************************/ +const char *VALUE::GetXfmt(void) + { + const char *fmt; + + switch (Type) { + case TYPE_STRING: fmt = "%*s"; break; + case TYPE_SHORT: fmt = (Unsigned) ? "%*hu" : "%*hd"; break; + case TYPE_BIGINT: fmt = (Unsigned) ? "%*llu" : "%*lld"; break; + case TYPE_FLOAT: fmt = "%*.*lf"; break; + default: fmt = (Unsigned) ? "%*u" : "%*d"; break; + } // endswitch Type + + return fmt; + } // end of GetFmt + +/* -------------------------- Class TYPVAL ---------------------------- */ + +/***********************************************************************/ +/* TYPVAL public constructor from a constant typed value. */ +/***********************************************************************/ +template +TYPVAL::TYPVAL(TYPE n, int type, int prec, bool un) + : VALUE(type, un) + { + Tval = n; + Clen = sizeof(TYPE); + Prec = prec; + } // end of TYPVAL constructor + +/***********************************************************************/ +/* Return unsigned max value for the type. */ +/***********************************************************************/ +template +ulonglong TYPVAL::MaxVal(void) {DBUG_ASSERT(false); return 0;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX16;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return UINT_MAX16;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX32;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return UINT_MAX32;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX8;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return UINT_MAX8;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX64;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return ULONGLONG_MAX;} + +/***********************************************************************/ +/* TYPVAL GetValLen: returns the print length of the typed object. */ +/***********************************************************************/ +template +int TYPVAL::GetValLen(void) + { + char c[32]; + + return sprintf(c, Fmt, Tval); + } // end of GetValLen + +template <> +int TYPVAL::GetValLen(void) + { + char c[32]; + + return sprintf(c, Fmt, Prec, Tval); + } // end of GetValLen + +/***********************************************************************/ +/* TYPVAL SetValue: copy the value of another Value object. */ +/* This function allows conversion if chktype is false. */ +/***********************************************************************/ +template +bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) + { + if (chktype && Type != valp->GetType()) + return true; + + if (!(Null = valp->IsNull() && Nullable)) + Tval = GetTypedValue(valp); + else + Reset(); + + return false; + } // end of SetValue + +template <> +short TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetShortValue();} + +template <> +ushort TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUShortValue();} + +template <> +int TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetIntValue();} + +template <> +uint TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUIntValue();} + +template <> +longlong TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetBigintValue();} + +template <> +ulonglong TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUBigintValue();} + +template <> +double TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetFloatValue();} + +template <> +char TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetTinyValue();} + +template <> +uchar TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUTinyValue();} + +/***********************************************************************/ +/* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/ +/***********************************************************************/ +template +bool TYPVAL::SetValue_char(char *p, int n) + { + bool rc, minus; + ulonglong maxval = MaxVal(); + ulonglong val = CharToNumber(p, n, maxval, Unsigned, &minus, &rc); + + if (minus && val < maxval) + Tval = (TYPE)(-(signed)val); + else + Tval = (TYPE)val; + + if (trace > 1) { + char buf[64]; + htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"), + GetTypeName(Type), Tval); + } // endif trace + + Null = false; + return rc; + } // end of SetValue + +template <> +bool TYPVAL::SetValue_char(char *p, int n) + { + if (p) { + char buf[32]; + + for (; n > 0 && *p == ' '; p++) + n--; + + memcpy(buf, p, min(n, 31)); + buf[n] = '\0'; + Tval = atof(buf); + + if (trace > 1) + htrc(" setting double: '%s' -> %lf\n", buf, Tval); + + Null = false; + } else { + Reset(); + Null = Nullable; + } // endif p + + return false; + } // end of SetValue + +/***********************************************************************/ +/* TYPVAL SetValue: fill a typed value from a string. */ +/***********************************************************************/ +template +void TYPVAL::SetValue_psz(PSZ s) + { + if (s) { + SetValue_char(s, (int)strlen(s)); + Null = false; + } else { + Reset(); + Null = Nullable; + } // endif p + + } // end of SetValue + +/***********************************************************************/ +/* TYPVAL SetValue: set value with a TYPE extracted from a block. */ +/***********************************************************************/ +template +void TYPVAL::SetValue_pvblk(PVBLK blk, int n) + { + Tval = GetTypedValue(blk, n); + Null = false; + } // end of SetValue + +template <> +int TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetIntValue(n);} + +template <> +uint TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetUIntValue(n);} + +template <> +short TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetShortValue(n);} + +template <> +ushort TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetUShortValue(n);} + +template <> +longlong TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetBigintValue(n);} + +template <> +ulonglong TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetUBigintValue(n);} + +template <> +double TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetFloatValue(n);} + +template <> +char TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetTinyValue(n);} + +template <> +uchar TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetUTinyValue(n);} + +/***********************************************************************/ +/* TYPVAL SetBinValue: with bytes extracted from a line. */ +/***********************************************************************/ +template +void TYPVAL::SetBinValue(void *p) + { + Tval = *(TYPE *)p; + Null = false; + } // end of SetBinValue + +/***********************************************************************/ +/* GetBinValue: fill a buffer with the internal binary value. */ +/* This function checks whether the buffer length is enough and */ +/* returns true if not. Actual filling occurs only if go is true. */ +/* Currently used by WriteColumn of binary files. */ +/***********************************************************************/ +template +bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) + { + // Test on length was removed here until a variable in column give the + // real field length. For BIN files the field length logically cannot + // be different from the variable length because no conversion is done. + // Therefore this test is useless anyway. +//#if defined(_DEBUG) +// if (sizeof(TYPE) > buflen) +// return true; +//#endif + + if (go) + *(TYPE *)buf = Tval; + + Null = false; + return false; + } // end of GetBinValue + +/***********************************************************************/ +/* TYPVAL ShowValue: get string representation of a typed value. */ +/***********************************************************************/ +template +char *TYPVAL::ShowValue(char *buf, int len) + { + sprintf(buf, Xfmt, len, Tval); + return buf; + } // end of ShowValue + +template <> +char *TYPVAL::ShowValue(char *buf, int len) + { + // TODO: use snprintf to avoid possible overflow + sprintf(buf, Xfmt, len, Prec, Tval); + return buf; + } // end of ShowValue + +/***********************************************************************/ +/* TYPVAL GetCharString: get string representation of a typed value. */ +/***********************************************************************/ +template +char *TYPVAL::GetCharString(char *p) + { + sprintf(p, Fmt, Tval); + return p; + } // end of GetCharString + +template <> +char *TYPVAL::GetCharString(char *p) + { + sprintf(p, Fmt, Prec, Tval); + return p; + } // end of GetCharString + +#if 0 +/***********************************************************************/ +/* TYPVAL GetShortString: get short representation of a typed value. */ +/***********************************************************************/ +template +char *TYPVAL::GetShortString(char *p, int n) + { + sprintf(p, "%*hd", n, (short)Tval); + return p; + } // end of GetShortString + +/***********************************************************************/ +/* TYPVAL GetIntString: get int representation of a typed value. */ +/***********************************************************************/ +template +char *TYPVAL::GetIntString(char *p, int n) + { + sprintf(p, "%*d", n, (int)Tval); + return p; + } // end of GetIntString + +/***********************************************************************/ +/* TYPVAL GetBigintString: get big int representation of a TYPE value.*/ +/***********************************************************************/ +template +char *TYPVAL::GetBigintString(char *p, int n) + { + sprintf(p, "%*lld", n, (longlong)Tval); + return p; + } // end of GetBigintString + +/***********************************************************************/ +/* TYPVAL GetFloatString: get double representation of a typed value. */ +/***********************************************************************/ +template +char *TYPVAL::GetFloatString(char *p, int n, int prec) + { + sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Tval); + return p; + } // end of GetFloatString + +/***********************************************************************/ +/* TYPVAL GetTinyString: get char representation of a typed value. */ +/***********************************************************************/ +template +char *TYPVAL::GetTinyString(char *p, int n) + { + sprintf(p, "%*d", n, (int)(char)Tval); + return p; + } // end of GetIntString +#endif // 0 + +/***********************************************************************/ +/* TYPVAL compare value with another Value. */ +/***********************************************************************/ +template +bool TYPVAL::IsEqual(PVAL vp, bool chktype) + { + if (this == vp) + return true; + else if (chktype && Type != vp->GetType()) + return false; + else if (chktype && Unsigned != vp->IsUnsigned()) + return false; + else if (Null || vp->IsNull()) + return false; + else + return (Tval == GetTypedValue(vp)); + + } // end of IsEqual + +/***********************************************************************/ +/* FormatValue: This function set vp (a STRING value) to the string */ +/* constructed from its own value formated using the fmt format. */ +/* This function assumes that the format matches the value type. */ +/***********************************************************************/ +template +bool TYPVAL::FormatValue(PVAL vp, char *fmt) + { + char *buf = (char*)vp->GetTo_Val(); // Should be big enough + int n = sprintf(buf, fmt, Tval); + + return (n > vp->GetValLen()); + } // end of FormatValue + +/***********************************************************************/ +/* TYPVAL SetFormat function (used to set SELECT output format). */ +/***********************************************************************/ +template +bool TYPVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt) + { + char c[32]; + + fmt.Type[0] = *GetFormatType(Type); + fmt.Length = sprintf(c, Fmt, Tval); + fmt.Prec = Prec; + return false; + } // end of SetConstFormat + +/***********************************************************************/ +/* Make file output of a typed object. */ +/***********************************************************************/ +template +void TYPVAL::Print(PGLOBAL g, FILE *f, uint n) + { + char m[64], buf[12]; + + memset(m, ' ', n); /* Make margin string */ + m[n] = '\0'; + + if (Null) + fprintf(f, "%s\n", m); + else + fprintf(f, strcat(strcat(strcpy(buf, "%s"), Fmt), "\n"), m, Tval); + + } /* end of Print */ + +/***********************************************************************/ +/* Make string output of a int object. */ +/***********************************************************************/ +template +void TYPVAL::Print(PGLOBAL g, char *ps, uint z) + { + if (Null) + strcpy(ps, ""); + else + sprintf(ps, Fmt, Tval); + + } /* end of Print */ + +/* -------------------------- Class STRING --------------------------- */ + +/***********************************************************************/ +/* STRING public constructor from a constant string. */ +/***********************************************************************/ +TYPVAL::TYPVAL(PSZ s) : VALUE(TYPE_STRING) + { + Strp = s; + Len = strlen(s); + Clen = Len; + Ci = false; + } // end of STRING constructor + +/***********************************************************************/ +/* STRING public constructor from char. */ +/***********************************************************************/ +TYPVAL::TYPVAL(PGLOBAL g, PSZ s, int n, int c) + : VALUE(TYPE_STRING) + { + Len = (g) ? n : strlen(s); + + if (!s) { + if (g) { + Strp = (char *)PlugSubAlloc(g, NULL, Len + 1); + Strp[Len] = '\0'; + } else + assert(false); + + } else + Strp = s; + + Clen = Len; + Ci = (c != 0); + } // end of STRING constructor + +/***********************************************************************/ +/* Get the tiny value represented by the Strp string. */ +/***********************************************************************/ +char TYPVAL::GetTinyValue(void) + { + bool m; + ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX8, false, &m); + + return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val; + } // end of GetTinyValue + +/***********************************************************************/ +/* Get the unsigned tiny value represented by the Strp string. */ +/***********************************************************************/ +uchar TYPVAL::GetUTinyValue(void) + { + return (uchar)CharToNumber(Strp, strlen(Strp), UINT_MAX8, true); + } // end of GetUTinyValue + +/***********************************************************************/ +/* Get the short value represented by the Strp string. */ +/***********************************************************************/ +short TYPVAL::GetShortValue(void) + { + bool m; + ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX16, false, &m); + + return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val; + } // end of GetShortValue + +/***********************************************************************/ +/* Get the unsigned short value represented by the Strp string. */ +/***********************************************************************/ +ushort TYPVAL::GetUShortValue(void) + { + return (ushort)CharToNumber(Strp, strlen(Strp), UINT_MAX16, true); + } // end of GetUshortValue + +/***********************************************************************/ +/* Get the integer value represented by the Strp string. */ +/***********************************************************************/ +int TYPVAL::GetIntValue(void) + { + bool m; + ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX32, false, &m); + + return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val; + } // end of GetIntValue + +/***********************************************************************/ +/* Get the unsigned integer value represented by the Strp string. */ +/***********************************************************************/ +uint TYPVAL::GetUIntValue(void) + { + return (uint)CharToNumber(Strp, strlen(Strp), UINT_MAX32, true); + } // end of GetUintValue + +/***********************************************************************/ +/* Get the big integer value represented by the Strp string. */ +/***********************************************************************/ +longlong TYPVAL::GetBigintValue(void) + { + bool m; + ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX64, false, &m); + + return (m && val < INT_MAX64) ? (-(signed)val) : (longlong)val; + } // end of GetBigintValue + +/***********************************************************************/ +/* Get the unsigned big integer value represented by the Strp string. */ +/***********************************************************************/ +ulonglong TYPVAL::GetUBigintValue(void) + { + return CharToNumber(Strp, strlen(Strp), ULONGLONG_MAX, true); + } // end of GetUBigintValue + +/***********************************************************************/ +/* STRING SetValue: copy the value of another Value object. */ +/***********************************************************************/ +bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) + { + if (chktype && (valp->GetType() != Type || valp->GetSize() > Len)) + return true; + + char buf[32]; + + if (!(Null = valp->IsNull() && Nullable)) + strncpy(Strp, valp->GetCharString(buf), Len); + else + Reset(); + + return false; + } // end of SetValue_pval + +/***********************************************************************/ +/* STRING SetValue: fill string with chars extracted from a line. */ +/***********************************************************************/ +bool TYPVAL::SetValue_char(char *p, int n) + { + bool rc; + + if (p) { + rc = n > Len; + + if ((n = min(n, Len))) { + strncpy(Strp, p, n); + +// for (p = Strp + n - 1; p >= Strp && (*p == ' ' || *p == '\0'); p--) ; + for (p = Strp + n - 1; p >= Strp; p--) + if (*p && *p != ' ') + break; + + *(++p) = '\0'; + + if (trace > 1) + htrc(" Setting string to: '%s'\n", Strp); + + } else + Reset(); + + Null = false; + } else { + rc = false; + Reset(); + Null = Nullable; + } // endif p + + return rc; + } // end of SetValue_char + +/***********************************************************************/ +/* STRING SetValue: fill string with another string. */ +/***********************************************************************/ +void TYPVAL::SetValue_psz(PSZ s) + { + if (s) { + strncpy(Strp, s, Len); + Null = false; + } else { + Reset(); + Null = Nullable; + } // endif s + + } // end of SetValue_psz + +/***********************************************************************/ +/* STRING SetValue: fill string with a string extracted from a block. */ +/***********************************************************************/ +void TYPVAL::SetValue_pvblk(PVBLK blk, int n) + { + strncpy(Strp, blk->GetCharValue(n), Len); + } // end of SetValue_pvblk + +/***********************************************************************/ +/* STRING SetValue: get the character representation of an integer. */ +/***********************************************************************/ +void TYPVAL::SetValue(int n) + { + char buf[16]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%d", n); + + if (k > Len) { + sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); + longjmp(g->jumper[g->jump_level], 138); + } else + SetValue_psz(buf); + + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of an uint. */ +/***********************************************************************/ +void TYPVAL::SetValue(uint n) + { + char buf[16]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%u", n); + + if (k > Len) { + sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); + longjmp(g->jumper[g->jump_level], 138); + } else + SetValue_psz(buf); + + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a short int. */ +/***********************************************************************/ +void TYPVAL::SetValue(short i) + { + SetValue((int)i); + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a ushort int. */ +/***********************************************************************/ +void TYPVAL::SetValue(ushort i) + { + SetValue((uint)i); + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a big integer.*/ +/***********************************************************************/ +void TYPVAL::SetValue(longlong n) + { + char buf[24]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%lld", n); + + if (k > Len) { + sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); + longjmp(g->jumper[g->jump_level], 138); + } else + SetValue_psz(buf); + + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a big integer.*/ +/***********************************************************************/ +void TYPVAL::SetValue(ulonglong n) + { + char buf[24]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%llu", n); + + if (k > Len) { + sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); + longjmp(g->jumper[g->jump_level], 138); + } else + SetValue_psz(buf); + + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a double. */ +/***********************************************************************/ +void TYPVAL::SetValue(double f) + { + char *p, buf[32]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%lf", f); + + for (p = buf + k - 1; p >= buf; p--) + if (*p == '0') { + *p = 0; + k--; + } else + break; + + if (k > Len) { + sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); + longjmp(g->jumper[g->jump_level], 138); + } else + SetValue_psz(buf); + + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a tiny int. */ +/***********************************************************************/ +void TYPVAL::SetValue(char c) + { + SetValue((int)c); + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a tiny int. */ +/***********************************************************************/ +void TYPVAL::SetValue(uchar c) + { + SetValue((uint)c); + Null = false; + } // end of SetValue + +/***********************************************************************/ +/* STRING SetBinValue: fill string with chars extracted from a line. */ +/***********************************************************************/ +void TYPVAL::SetBinValue(void *p) + { + SetValue_char((char *)p, Len); + } // end of SetBinValue + +/***********************************************************************/ +/* GetBinValue: fill a buffer with the internal binary value. */ +/* This function checks whether the buffer length is enough and */ +/* returns true if not. Actual filling occurs only if go is true. */ +/* Currently used by WriteColumn of binary files. */ +/***********************************************************************/ +bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) + { + int len = (Null) ? 0 : strlen(Strp); + + if (len > buflen) + return true; + else if (go) { + memset(buf, ' ', buflen); + memcpy(buf, Strp, len); + } // endif go + + return false; + } // end of GetBinValue + +/***********************************************************************/ +/* STRING ShowValue: get string representation of a char value. */ +/***********************************************************************/ +char *TYPVAL::ShowValue(char *buf, int len) + { + return Strp; + } // end of ShowValue + +/***********************************************************************/ +/* STRING GetCharString: get string representation of a char value. */ +/***********************************************************************/ +char *TYPVAL::GetCharString(char *p) + { + return Strp; + } // end of GetCharString + +/***********************************************************************/ +/* STRING compare value with another Value. */ +/***********************************************************************/ +bool TYPVAL::IsEqual(PVAL vp, bool chktype) + { + if (this == vp) + return true; + else if (chktype && Type != vp->GetType()) + return false; + else if (Null || vp->IsNull()) + return false; + + char buf[32]; + + if (Ci || vp->IsCi()) + return !stricmp(Strp, vp->GetCharString(buf)); + else // (!Ci) + return !strcmp(Strp, vp->GetCharString(buf)); + + } // end of IsEqual + +/***********************************************************************/ +/* FormatValue: This function set vp (a STRING value) to the string */ +/* constructed from its own value formated using the fmt format. */ +/* This function assumes that the format matches the value type. */ +/***********************************************************************/ +bool TYPVAL::FormatValue(PVAL vp, char *fmt) + { + char *buf = (char*)vp->GetTo_Val(); // Should be big enough + int n = sprintf(buf, fmt, Strp); + + return (n > vp->GetValLen()); + } // end of FormatValue + +/***********************************************************************/ +/* STRING SetFormat function (used to set SELECT output format). */ +/***********************************************************************/ +bool TYPVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt) + { + fmt.Type[0] = 'C'; + fmt.Length = Len; + fmt.Prec = 0; + return false; + } // end of SetConstFormat + +/* -------------------------- Class DTVAL ---------------------------- */ + +/***********************************************************************/ +/* DTVAL public constructor for new void values. */ +/***********************************************************************/ +DTVAL::DTVAL(PGLOBAL g, int n, int prec, PSZ fmt) + : TYPVAL((int)0, TYPE_DATE) + { + if (!fmt) { + Pdtp = NULL; + Sdate = NULL; + DefYear = 0; + Len = n; + } else + SetFormat(g, fmt, n, prec); + +//Type = TYPE_DATE; + } // end of DTVAL constructor + +/***********************************************************************/ +/* DTVAL public constructor from int. */ +/***********************************************************************/ +DTVAL::DTVAL(PGLOBAL g, int n) : TYPVAL(n, TYPE_DATE) + { + Pdtp = NULL; + Len = 19; +//Type = TYPE_DATE; + Sdate = NULL; + DefYear = 0; + } // end of DTVAL constructor + +/***********************************************************************/ +/* Set format so formatted dates can be converted on input/output. */ +/***********************************************************************/ +bool DTVAL::SetFormat(PGLOBAL g, PSZ fmt, int len, int year) + { + Pdtp = MakeDateFormat(g, fmt, true, true, (year > 9999) ? 1 : 0); + Sdate = (char*)PlugSubAlloc(g, NULL, len + 1); + DefYear = (int)((year > 9999) ? (year - 10000) : year); + Len = len; + return false; + } // end of SetFormat + +/***********************************************************************/ +/* Set format from the format of another date value. */ +/***********************************************************************/ +bool DTVAL::SetFormat(PGLOBAL g, PVAL valp) + { + DTVAL *vp; + + if (valp->GetType() != TYPE_DATE) { + sprintf(g->Message, MSG(NO_FORMAT_TYPE), valp->GetType()); + return true; + } else + vp = (DTVAL*)valp; + + Len = vp->Len; + Pdtp = vp->Pdtp; + Sdate = (char*)PlugSubAlloc(g, NULL, Len + 1); + DefYear = vp->DefYear; + return false; + } // end of SetFormat + +/***********************************************************************/ +/* We need TimeShift because the mktime C function does a correction */ +/* for local time zone that we want to override for DB operations. */ +/***********************************************************************/ +void DTVAL::SetTimeShift(void) + { + struct tm dtm; + memset(&dtm, 0, sizeof(dtm)); + dtm.tm_mday=2; + dtm.tm_mon=0; + dtm.tm_year=70; + + Shift = (int)mktime(&dtm) - 86400; + + if (trace) + htrc("DTVAL Shift=%d\n", Shift); + + } // end of SetTimeShift + +// Added by Alexander Barkov +static void TIME_to_localtime(struct tm *tm, const MYSQL_TIME *ltime) +{ + bzero(tm, sizeof(*tm)); + tm->tm_year= ltime->year - 1900; + tm->tm_mon= ltime->month - 1; + tm->tm_mday= ltime->day; + tm->tm_hour= ltime->hour; + tm->tm_min= ltime->minute; + tm->tm_sec= ltime->second; +} + +// Added by Alexander Barkov +static struct tm *gmtime_mysql(const time_t *timep, struct tm *tm) +{ + MYSQL_TIME ltime; + thd_gmt_sec_to_TIME(current_thd, <ime, (my_time_t) *timep); + TIME_to_localtime(tm, <ime); + return tm; +} + +/***********************************************************************/ +/* GetGmTime: returns a pointer to a static tm structure obtained */ +/* though the gmtime C function. The purpose of this function is to */ +/* extend the range of valid dates by accepting negative time values. */ +/***********************************************************************/ +struct tm *DTVAL::GetGmTime(struct tm *tm_buffer) + { + struct tm *datm; + time_t t = (time_t)Tval; + + if (Tval < 0) { + int n; + + for (n = 0; t < 0; n += 4) + t += FOURYEARS; + + datm = gmtime_mysql(&t, tm_buffer); + + if (datm) + datm->tm_year -= n; + + } else + datm = gmtime_mysql(&t, tm_buffer); + + return datm; + } // end of GetGmTime + +// Added by Alexander Barkov +static time_t mktime_mysql(struct tm *ptm) +{ + MYSQL_TIME ltime; + localtime_to_TIME(<ime, ptm); + ltime.time_type= MYSQL_TIMESTAMP_DATETIME; + uint error_code; + time_t t= TIME_to_timestamp(current_thd, <ime, &error_code); + return error_code ? (time_t) -1 : t; +} + +/***********************************************************************/ +/* MakeTime: calculates a date value from a tm structures using the */ +/* mktime C function. The purpose of this function is to extend the */ +/* range of valid dates by accepting to set negative time values. */ +/***********************************************************************/ +bool DTVAL::MakeTime(struct tm *ptm) + { + int n, y = ptm->tm_year; + time_t t = mktime_mysql(ptm); + + if (trace > 1) + htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n", + ptm->tm_year, ptm->tm_mon, ptm->tm_mday, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + + if (t == -1) { + if (y < 1 || y > 71) + return true; + + for (n = 0; t == -1 && n < 20; n++) { + ptm->tm_year += 4; + t = mktime_mysql(ptm); + } // endfor t + + if (t == -1) + return true; + + if ((t -= (n * FOURYEARS)) > 2000000000) + return true; + + } + Tval= (int) t; + + if (trace > 1) + htrc("MakeTime Ival=%d\n", Tval); + + return false; + } // end of MakeTime + +/***********************************************************************/ +/* Make a time_t datetime from its components (YY, MM, DD, hh, mm, ss) */ +/***********************************************************************/ +bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) + { + int i, m; + int n; + bool rc = false; + struct tm datm; + bzero(&datm, sizeof(datm)); + datm.tm_mday=1; + datm.tm_mon=0; + datm.tm_year=70; + + if (trace > 1) + htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n", + val[0], val[1], val[2], val[3], val[4], val[5], nval); + + for (i = 0; i < nval; i++) { + n = val[i]; + +// if (trace > 1) +// htrc("i=%d n=%d\n", i, n); + + switch (i) { + case 0: + if (n >= 1900) + n -= 1900; + + datm.tm_year = n; + +// if (trace > 1) +// htrc("n=%d tm_year=%d\n", n, datm.tm_year); + + break; + case 1: + // If mktime handles apparently correctly large or negative + // day values, it is not the same for months. Therefore we + // do the ajustment here, thus mktime has not to do it. + if (n > 0) { + m = (n - 1) % 12; + n = (n - 1) / 12; + } else { + m = 11 + n % 12; + n = n / 12 - 1; + } // endfi n + + datm.tm_mon = m; + datm.tm_year += n; + +// if (trace > 1) +// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon); + + break; + case 2: + // For days, big or negative values may also cause problems + m = n % 1461; + n = 4 * (n / 1461); + + if (m < 0) { + m += 1461; + n -= 4; + } // endif m + + datm.tm_mday = m; + datm.tm_year += n; + +// if (trace > 1) +// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon); + + break; + case 3: datm.tm_hour = n; break; + case 4: datm.tm_min = n; break; + case 5: datm.tm_sec = n; break; + } // endswitch i + + } // endfor i + + if (trace > 1) + htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n", + datm.tm_year, datm.tm_mon, datm.tm_mday, + datm.tm_hour, datm.tm_min, datm.tm_sec); + + // Pass g to have an error return or NULL to set invalid dates to 0 + if (MakeTime(&datm)) + if (g) { + strcpy(g->Message, MSG(BAD_DATETIME)); + rc = true; + } else + Tval = 0; + + return rc; + } // end of MakeDate + +/***********************************************************************/ +/* DTVAL SetValue: copy the value of another Value object. */ +/* This function allows conversion if chktype is false. */ +/***********************************************************************/ +bool DTVAL::SetValue_pval(PVAL valp, bool chktype) + { + if (chktype && Type != valp->GetType()) + return true; + + if (!(Null = valp->IsNull() && Nullable)) { + if (Pdtp && !valp->IsTypeNum()) { + int ndv; + int dval[6]; + + ndv = ExtractDate(valp->GetCharValue(), Pdtp, DefYear, dval); + MakeDate(NULL, dval, ndv); + } else + Tval = valp->GetIntValue(); + + } else + Reset(); + + return false; + } // end of SetValue + +/***********************************************************************/ +/* SetValue: convert chars extracted from a line to date value. */ +/***********************************************************************/ +bool DTVAL::SetValue_char(char *p, int n) + { + bool rc; + + if (Pdtp) { + char *p2; + int ndv; + int dval[6]; + + // Trim trailing blanks + for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--) ; + + if ((rc = (n = p2 - p + 1) > Len)) + n = Len; + + memcpy(Sdate, p, n); + Sdate[n] = '\0'; + + ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); + MakeDate(NULL, dval, ndv); + + if (trace > 1) + htrc(" setting date: '%s' -> %d\n", Sdate, Tval); + + Null = false; + } else + rc = TYPVAL::SetValue_char(p, n); + + return rc; + } // end of SetValue + +/***********************************************************************/ +/* SetValue: convert a char string to date value. */ +/***********************************************************************/ +void DTVAL::SetValue_psz(PSZ p) + { + if (Pdtp) { + int ndv; + int dval[6]; + + strncpy(Sdate, p, Len); + Sdate[Len] = '\0'; + + ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); + MakeDate(NULL, dval, ndv); + + if (trace > 1) + htrc(" setting date: '%s' -> %d\n", Sdate, Tval); + + Null = false; + } else + TYPVAL::SetValue_psz(p); + + } // end of SetValue + +/***********************************************************************/ +/* DTVAL SetValue: set value with a value extracted from a block. */ +/***********************************************************************/ +void DTVAL::SetValue_pvblk(PVBLK blk, int n) + { + if (Pdtp && !::IsTypeNum(blk->GetType())) { + int ndv; + int dval[6]; + + ndv = ExtractDate(blk->GetCharValue(n), Pdtp, DefYear, dval); + MakeDate(NULL, dval, ndv); + } else + Tval = blk->GetIntValue(n); + + } // end of SetValue + +/***********************************************************************/ +/* DTVAL GetCharString: get string representation of a date value. */ +/***********************************************************************/ +char *DTVAL::GetCharString(char *p) + { + if (Pdtp) { + size_t n = 0; + struct tm tm, *ptm= GetGmTime(&tm); + + if (ptm) + n = strftime(Sdate, Len + 1, Pdtp->OutFmt, ptm); + + if (!n) { + *Sdate = '\0'; + strncat(Sdate, "Error", Len + 1); + } // endif n + + return Sdate; + } else + sprintf(p, "%d", Tval); + + Null = false; + return p; + } // end of GetCharString + +/***********************************************************************/ +/* DTVAL ShowValue: get string representation of a date value. */ +/***********************************************************************/ +char *DTVAL::ShowValue(char *buf, int len) + { + if (Pdtp) { + char *p; + size_t m, n = 0; + struct tm tm, *ptm = GetGmTime(&tm); + + if (Len < len) { + p = buf; + m = len; + } else { + p = Sdate; + m = Len + 1; + } // endif Len + + if (ptm) + n = strftime(p, m, Pdtp->OutFmt, ptm); + + if (!n) { + *p = '\0'; + strncat(p, "Error", m); + } // endif n + + return p; + } else + return TYPVAL::ShowValue(buf, len); + + } // end of ShowValue + +#if 0 // Not used by CONNECT +/***********************************************************************/ +/* Returns a member of the struct tm representation of the date. */ +/***********************************************************************/ +bool DTVAL::GetTmMember(OPVAL op, int& mval) + { + bool rc = false; + struct tm tm, *ptm = GetGmTime(&tm); + + switch (op) { + case OP_MDAY: mval = ptm->tm_mday; break; + case OP_MONTH: mval = ptm->tm_mon + 1; break; + case OP_YEAR: mval = ptm->tm_year + 1900; break; + case OP_WDAY: mval = ptm->tm_wday + 1; break; + case OP_YDAY: mval = ptm->tm_yday + 1; break; + case OP_QUART: mval = ptm->tm_mon / 3 + 1; break; + default: + rc = true; + } // endswitch op + + return rc; + } // end of GetTmMember + +/***********************************************************************/ +/* Calculates the week number of the year for the internal date value.*/ +/* The International Standard ISO 8601 has decreed that Monday shall */ +/* be the first day of the week. A week that lies partly in one year */ +/* and partly in another is assigned a number in the year in which */ +/* most of its days lie. That means that week number 1 of any year is */ +/* the week that contains the January 4th. */ +/***********************************************************************/ +bool DTVAL::WeekNum(PGLOBAL g, int& nval) + { + // w is the start of the week SUN=0, MON=1, etc. + int m, n, w = nval % 7; + struct tm tm, *ptm = GetGmTime(&tm); + + // Which day is January 4th of this year? + m = (367 + ptm->tm_wday - ptm->tm_yday) % 7; + + // When does the first week begins? + n = 3 - (7 + m - w) % 7; + + // Now calculate the week number + if (!(nval = (7 + ptm->tm_yday - n) / 7)) + nval = 52; + + // Everything should be Ok + return false; + } // end of WeekNum +#endif // 0 + +/***********************************************************************/ +/* FormatValue: This function set vp (a STRING value) to the string */ +/* constructed from its own value formated using the fmt format. */ +/* This function assumes that the format matches the value type. */ +/***********************************************************************/ +bool DTVAL::FormatValue(PVAL vp, char *fmt) + { + char *buf = (char*)vp->GetTo_Val(); // Should be big enough + struct tm tm, *ptm = GetGmTime(&tm); + + if (trace) + htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen()); + + if (ptm) { + size_t n = strftime(buf, vp->GetValLen(), fmt, ptm); + + if (trace) + htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???"); + + return (n == 0); + } else + return true; + + } // end of FormatValue + +/* -------------------------- End of Value --------------------------- */ diff --git a/storage/connect/value.h b/storage/connect/value.h index 5dc4ef98d51..185234b42b9 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -16,11 +16,6 @@ #include "assert.h" #include "block.h" -#if defined(WIN32) -#define strtoll _strtoi64 -#define atoll(S) strtoll(S, NULL, 10) -#endif // WIN32 - /***********************************************************************/ /* Types used in some class definitions. */ /***********************************************************************/ @@ -55,6 +50,8 @@ DllExport bool IsTypeNum(int type); DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0); DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 0, PSZ fmt = NULL); +DllExport ulonglong CharToNumber(char *, int, ulonglong, bool, + bool *minus = NULL, bool *rc = NULL); /***********************************************************************/ /* Class VALUE represents a constant or variable of any valid type. */ @@ -96,7 +93,7 @@ class DllExport VALUE : public BLOCK { // Methods virtual bool SetValue_pval(PVAL valp, bool chktype = false) = 0; - virtual void SetValue_char(char *p, int n) = 0; + virtual bool SetValue_char(char *p, int n) = 0; virtual void SetValue_psz(PSZ s) = 0; virtual void SetValue(char c) {assert(false);} virtual void SetValue(uchar c) {assert(false);} @@ -112,11 +109,6 @@ class DllExport VALUE : public BLOCK { virtual bool GetBinValue(void *buf, int buflen, bool go) = 0; virtual char *ShowValue(char *buf, int len = 0) = 0; virtual char *GetCharString(char *p) = 0; -//virtual char *GetShortString(char *p, int n) {return "#####";} -//virtual char *GetIntString(char *p, int n) = 0; -//virtual char *GetBigintString(char *p, int n) = 0; -//virtual char *GetFloatString(char *p, int n, int prec) = 0; -//virtual char *GetTinyString(char *p, int n) {return "?";} virtual bool IsEqual(PVAL vp, bool chktype) = 0; virtual bool FormatValue(PVAL vp, char *fmt) = 0; @@ -169,7 +161,7 @@ class DllExport TYPVAL : public VALUE { // Methods virtual bool SetValue_pval(PVAL valp, bool chktype); - virtual void SetValue_char(char *p, int n); + virtual bool SetValue_char(char *p, int n); virtual void SetValue_psz(PSZ s); virtual void SetValue(char c) {Tval = (TYPE)c; Null = false;} virtual void SetValue(uchar c) {Tval = (TYPE)c; Null = false;} @@ -185,11 +177,6 @@ class DllExport TYPVAL : public VALUE { virtual bool GetBinValue(void *buf, int buflen, bool go); virtual char *ShowValue(char *buf, int); virtual char *GetCharString(char *p); -//virtual char *GetShortString(char *p, int n); -//virtual char *GetIntString(char *p, int n); -//virtual char *GetBigintString(char *p, int n); -//virtual char *GetFloatString(char *p, int n, int prec = -1); -//virtual char *GetTinyString(char *p, int n); virtual bool IsEqual(PVAL vp, bool chktype); virtual bool SetConstFormat(PGLOBAL, FORMAT&); virtual bool FormatValue(PVAL vp, char *fmt); @@ -201,9 +188,10 @@ class DllExport TYPVAL : public VALUE { TYPVAL(void) : VALUE(TYPE_ERROR) {} // Specialized functions - TYPE GetTypedValue(PVAL vp); - TYPE GetTypedValue(PVBLK blk, int n); - TYPE GetTypedValue(PSZ s); + static ulonglong MaxVal(void); + TYPE GetTypedValue(PVAL vp); + TYPE GetTypedValue(PVBLK blk, int n); +// TYPE GetTypedValue(PSZ s); // Members TYPE Tval; @@ -227,21 +215,21 @@ class DllExport TYPVAL: public VALUE { virtual int GetValPrec() {return (Ci) ? 1 : 0;} virtual int GetSize(void) {return (Strp) ? strlen(Strp) : 0;} virtual PSZ GetCharValue(void) {return Strp;} - virtual char GetTinyValue(void) {return (char)atoi(Strp);} - virtual uchar GetUTinyValue(void) {return (uchar)atoi(Strp);} - virtual short GetShortValue(void) {return (short)atoi(Strp);} - virtual ushort GetUShortValue(void) {return (ushort)atoi(Strp);} - virtual int GetIntValue(void) {return atol(Strp);} - virtual uint GetUIntValue(void) {return (uint)atol(Strp);} - virtual longlong GetBigintValue(void) {return atoll(Strp);} - virtual ulonglong GetUBigintValue(void) {return (ulonglong)atoll(Strp);} + virtual char GetTinyValue(void); + virtual uchar GetUTinyValue(void); + virtual short GetShortValue(void); + virtual ushort GetUShortValue(void); + virtual int GetIntValue(void); + virtual uint GetUIntValue(void); + virtual longlong GetBigintValue(void); + virtual ulonglong GetUBigintValue(void); virtual double GetFloatValue(void) {return atof(Strp);} virtual void *GetTo_Val(void) {return Strp;} virtual void SetPrec(int prec) {Ci = prec != 0;} // Methods virtual bool SetValue_pval(PVAL valp, bool chktype); - virtual void SetValue_char(char *p, int n); + virtual bool SetValue_char(char *p, int n); virtual void SetValue_psz(PSZ s); virtual void SetValue_pvblk(PVBLK blk, int n); virtual void SetValue(char c); @@ -257,23 +245,10 @@ class DllExport TYPVAL: public VALUE { virtual bool GetBinValue(void *buf, int buflen, bool go); virtual char *ShowValue(char *buf, int); virtual char *GetCharString(char *p); -//virtual char *GetShortString(char *p, int n); -//virtual char *GetIntString(char *p, int n); -//virtual char *GetBigintString(char *p, int n); -//virtual char *GetFloatString(char *p, int n, int prec = -1); -//virtual char *GetTinyString(char *p, int n); virtual bool IsEqual(PVAL vp, bool chktype); virtual bool FormatValue(PVAL vp, char *fmt); virtual bool SetConstFormat(PGLOBAL, FORMAT&); - // Specialized functions -//template -//T GetValue_as(T type) {return Strp;} -//int GetValue_as(int type) {return atol(Strp);} -//short GetValue_as(short type) {return (short)atoi(Strp);} -//longlong GetValue_as(longlong type) {return atoll(Strp);} -//double GetValue_as(double type) {return atof(Strp);} - // Members PSZ Strp; bool Ci; // true if case insensitive @@ -295,7 +270,7 @@ class DllExport DTVAL : public TYPVAL { // Implementation virtual bool SetValue_pval(PVAL valp, bool chktype); - virtual void SetValue_char(char *p, int n); + virtual bool SetValue_char(char *p, int n); virtual void SetValue_psz(PSZ s); virtual void SetValue_pvblk(PVBLK blk, int n); virtual char *GetCharString(char *p); @@ -304,15 +279,15 @@ class DllExport DTVAL : public TYPVAL { bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0); bool SetFormat(PGLOBAL g, PVAL valp); bool IsFormatted(void) {return Pdtp != NULL;} - bool GetTmMember(OPVAL op, int& mval); - bool DateDiff(DTVAL *dtp, OPVAL op, int& tdif); +// bool GetTmMember(OPVAL op, int& mval); +// bool DateDiff(DTVAL *dtp, OPVAL op, int& tdif); bool MakeTime(struct tm *ptm); static void SetTimeShift(void); static int GetShift(void) {return Shift;} // Methods bool MakeDate(PGLOBAL g, int *val, int nval); - bool WeekNum(PGLOBAL g, int& nval); +// bool WeekNum(PGLOBAL g, int& nval); struct tm *GetGmTime(struct tm *); diff --git a/storage/connect/xobject.cpp b/storage/connect/xobject.cpp index cd8af248005..3da78426e95 100644 --- a/storage/connect/xobject.cpp +++ b/storage/connect/xobject.cpp @@ -134,6 +134,7 @@ bool CONSTANT::Compare(PXOB xp) } // end of Compare +#if 0 /***********************************************************************/ /* Rephrase: temporary implementation used by PlugRephraseSQL. */ /***********************************************************************/ @@ -166,6 +167,7 @@ bool CONSTANT::Rephrase(PGLOBAL g, PSZ work) return false; } // end of Rephrase +#endif // 0 /***********************************************************************/ /* Make file output of a constant object. */ diff --git a/storage/connect/xobject.h b/storage/connect/xobject.h index 79325f155cf..74d571a6e60 100644 --- a/storage/connect/xobject.h +++ b/storage/connect/xobject.h @@ -124,7 +124,7 @@ class DllExport CONSTANT : public XOBJECT { {return Value->SetConstFormat(g, fmt);} virtual int CheckSpcCol(PTDB, int) {return 1;} void Convert(PGLOBAL g, int newtype); - bool Rephrase(PGLOBAL g, PSZ work); +// bool Rephrase(PGLOBAL g, PSZ work); void SetValue(PVAL vp) {Value = vp;} virtual bool VerifyColumn(PTBX txp) {return true;} virtual bool VerifyTdb(PTDB& tdbp) {return true;}