Skip to content

Commit

Permalink
dblib: introduce dbanydatecrack
Browse files Browse the repository at this point in the history
This function is used to extract information from any kind of date/time.
dbdatecrack handle only DBDATETIME type so add a parameter (type) to
be able to handle all. A new DBDATEREC2 type is introduced to save
nanosecond precision time.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
  • Loading branch information
freddy77 committed Nov 22, 2015
1 parent c570def commit 8bebc32
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 27 deletions.
40 changes: 38 additions & 2 deletions include/sybdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,10 +483,45 @@ struct tds_sybase_dbdaterec
DBINT datetzone; /* 0 - 127 */
};

struct tds_microsoft_dbdaterec2
{
DBINT year; /* 1753 - 9999 */
DBINT quarter; /* 1 - 4 */
DBINT month; /* 1 - 12 */
DBINT day; /* 1 - 31 */
DBINT dayofyear; /* 1 - 366 */
DBINT week; /* 1 - 54 (for leap years) */
DBINT weekday; /* 1 - 7 (Mon. - Sun.) */
DBINT hour; /* 0 - 23 */
DBINT minute; /* 0 - 59 */
DBINT second; /* 0 - 59 */
DBINT nanosecond; /* 0 - 999999999 */
DBINT tzone; /* 0 - 127 (Sybase only) */
};

struct tds_sybase_dbdaterec2
{
DBINT dateyear; /* 1900 and counting */
DBINT quarter; /* 0 - 3 (Microsoft only) */
DBINT datemonth; /* 0 - 11 */
DBINT datedmonth; /* 1 - 31 */
DBINT datedyear; /* 1 - 366 */
DBINT week; /* 1 - 54 (Microsoft only) */
DBINT datedweek; /* 0 - 6 */
DBINT datehour; /* 0 - 23 */
DBINT dateminute; /* 0 - 59 */
DBINT datesecond; /* 0 - 59 */
DBINT datensecond; /* 0 - 999999999 */
DBINT datetzone; /* 0 - 127 */
};


#ifdef MSDBLIB
typedef struct tds_microsoft_dbdaterec DBDATEREC;
typedef struct tds_microsoft_dbdaterec DBDATEREC;
typedef struct tds_microsoft_dbdaterec2 DBDATEREC2;
#else
typedef struct tds_sybase_dbdaterec DBDATEREC;
typedef struct tds_sybase_dbdaterec DBDATEREC;
typedef struct tds_sybase_dbdaterec2 DBDATEREC2;
#endif

typedef int (*EHANDLEFUNC) (DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr);
Expand Down Expand Up @@ -717,6 +752,7 @@ DBINT dbcurrow(DBPROCESS * dbproc);
BYTE *dbdata(DBPROCESS * dbproc, int column);
int dbdatecmp(DBPROCESS * dbproc, DBDATETIME * d1, DBDATETIME * d2);
RETCODE dbdatecrack(DBPROCESS * dbproc, DBDATEREC * di, DBDATETIME * dt);
RETCODE dbanydatecrack(DBPROCESS * dbproc, DBDATEREC2 * di, int type, const void *data);
DBINT dbdatlen(DBPROCESS * dbproc, int column);
DBBOOL dbdead(DBPROCESS * dbproc);

Expand Down
3 changes: 2 additions & 1 deletion src/dblib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ if MINGW32
libsybdb_la_SOURCES += winmain.c
endif
EXTRA_DIST = dbopen.c buffering.h CMakeLists.txt winmain.c dblib.def
libsybdb_la_LDFLAGS= -version-info 5:0:0 $(FREETDS_SYMBOLIC)
# bumped for dbanydatecrack
libsybdb_la_LDFLAGS= -version-info 5:1:0 $(FREETDS_SYMBOLIC)
if !MACOSX
libsybdb_la_LDFLAGS += -export-symbols-regex '^(db|bcp_|tdsdump_open|tdsdbopen|.*_xact|close_commit|open_commit|.?asprintf).*'
endif
Expand Down
78 changes: 55 additions & 23 deletions src/dblib/dblib.c
Original file line number Diff line number Diff line change
Expand Up @@ -5591,34 +5591,18 @@ dbdatecmp(DBPROCESS * dbproc, DBDATETIME * d1, DBDATETIME * d2)
return 1;
}

/**
* \ingroup dblib_core
* \brief Break a DBDATETIME value into useful pieces.
*
* \param dbproc contains all information needed by db-lib to manage communications with the server.
* \param di \em output: structure to contain the exploded parts of \a datetime.
* \param datetime \em input: \c DBDATETIME to be converted.
* \retval SUCCEED always.
* \remarks The members of \a di have different names, depending on whether \c --with-msdblib was configured.
*
* If DBPROCESS is NULL, dbdatecrack() uses the compiled in default
* value of MSDBLIB as of when libsybdb was compiled, irrespective of its value when the
* application is compiled. This can lead to incorrect results because Sybase and Microsoft use different
* ranges -- [0,11] vs. [1,12] -- for the month.
*
* \sa dbconvert(), dbdata(), dbdatechar(), dbdatename(), dbdatepart(), tdsdbopen().
*/
RETCODE
dbdatecrack(DBPROCESS * dbproc, DBDATEREC * output, DBDATETIME * datetime)
static RETCODE
dblib_datecrack(DBPROCESS * dbproc, BOOL output2, DBDATEREC * output, int type, const void * data)
{
TDSDATEREC dr;
struct tds_sybase_dbdaterec *di = (struct tds_sybase_dbdaterec*) output;

tdsdump_log(TDS_DBG_FUNC, "dbdatecrack(%p, %p, %p)\n", dbproc, output, datetime);
tdsdump_log(TDS_DBG_FUNC, "dblib_datecrack(%p, %d, %p, %d, %p)\n", dbproc, output2, output, type, data);
CHECK_NULP(output, "dbdatecrack", 2, FAIL);
CHECK_PARAMETER(datetime, SYBENDTP, FAIL);
CHECK_PARAMETER(data, SYBENDTP, FAIL);

tds_datecrack(SYBDATETIME, datetime, &dr);
if (TDS_FAILED(tds_datecrack(type, data, &dr)))
return FAIL;

di->dateyear = dr.year;
di->quarter = dr.quarter;
Expand All @@ -5629,7 +5613,11 @@ dbdatecrack(DBPROCESS * dbproc, DBDATEREC * output, DBDATETIME * datetime)
di->datehour = dr.hour;
di->dateminute = dr.minute;
di->datesecond = dr.second;
di->datemsecond = dr.decimicrosecond / 10000u;
if (output2)
/* here we are writing to nanosecond field */
di->datemsecond = dr.decimicrosecond * 100u;
else
di->datemsecond = dr.decimicrosecond / 10000u;
/* Revert to compiled-in default if dbproc can't be used to find the runtime override. */
if (dbproc ? dbproc->msdblib : dblib_msdblib) {
++di->quarter;
Expand All @@ -5639,6 +5627,50 @@ dbdatecrack(DBPROCESS * dbproc, DBDATEREC * output, DBDATETIME * datetime)
return SUCCEED;
}

/**
* \ingroup dblib_core
* \brief Break a DBDATETIME value into useful pieces.
*
* \param dbproc contains all information needed by db-lib to manage communications with the server.
* \param di \em output: structure to contain the exploded parts of \a datetime.
* \param datetime \em input: \c DBDATETIME to be converted.
* \retval SUCCEED always.
* \remarks The members of \a di have different names, depending on whether \c --with-msdblib was configured.
*
* If DBPROCESS is NULL, dbdatecrack() uses the compiled in default
* value of MSDBLIB as of when libsybdb was compiled, irrespective of its value when the
* application is compiled. This can lead to incorrect results because Sybase and Microsoft use different
* ranges -- [0,11] vs. [1,12] -- for the month.
*
* \sa dbconvert(), dbdata(), dbdatechar(), dbdatename(), dbdatepart(), tdsdbopen().
*/
RETCODE
dbdatecrack(DBPROCESS * dbproc, DBDATEREC * di, DBDATETIME * datetime)
{
return dblib_datecrack(dbproc, FALSE, di, SYBDATETIME, datetime);
}

/**
* \ingroup dblib_core
* \brief Break any kind of date or time value into useful pieces.
*
* \param dbproc contains all information needed by db-lib to manage communications with the server.
* \param di \em output: structure to contain the exploded parts of \a datetime.
* \param type \em input: \c type of date/time value returned by dbcoltype().
* \param data \em input: \c date/time value to be converted.
* \retval SUCCEED always.
* \remarks The members of \a di have different names, depending on whether \c --with-msdblib was configured.
*
* This is an extension to dbdatecrack(), see it for more information.
*
* \sa dbdatecrack(), dbconvert(), dbdata(), dbdatechar(), dbdatename(), dbdatepart(), tdsdbopen().
*/
RETCODE
dbanydatecrack(DBPROCESS * dbproc, DBDATEREC2 * di, int type, const void *data)
{
return dblib_datecrack(dbproc, TRUE, (DBDATEREC *) di, type, data);
}

#if defined(DBLIB_UNIMPLEMENTED)
/**
* \ingroup dblib_core
Expand Down
40 changes: 39 additions & 1 deletion src/dblib/unittests/t0012.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ main(int argc, char *argv[])
LOGINREC *login;
DBPROCESS *dbproc;
char datestring[256];
DBDATEREC dateinfo;
DBDATEREC dateinfo;
#ifdef SYBMSDATETIME2
DBDATEREC2 dateinfo2;
#endif
DBDATETIME mydatetime;
int output_count = 0;

Expand Down Expand Up @@ -118,9 +121,44 @@ main(int argc, char *argv[])
if (output_count != 2)
set_failed();

#ifdef SYBMSDATETIME2
/* select */
sql_cmd(dbproc);
dbsqlexec(dbproc);
dbresults(dbproc);

while (dbnextrow(dbproc) != NO_MORE_ROWS) {
++output_count;
/* Print the date info */
dbconvert(dbproc, dbcoltype(dbproc, 1), dbdata(dbproc, 1), dbdatlen(dbproc, 1), SYBCHAR, (BYTE*) datestring, -1);

printf("%s\n", datestring);

/* Break up the creation date into its constituent parts */
if (dbanydatecrack(dbproc, &dateinfo2, dbcoltype(dbproc, 1), dbdata(dbproc, 1)) != SUCCEED)
set_failed();

/* Print the parts of the creation date */
printf("\tYear = %d.\n", dateinfo2.dateyear);
printf("\tMonth = %d.\n", dateinfo2.datemonth);
printf("\tDay of month = %d.\n", dateinfo2.datedmonth);
printf("\tDay of year = %d.\n", dateinfo2.datedyear);
printf("\tDay of week = %d.\n", dateinfo2.datedweek);
printf("\tHour = %d.\n", dateinfo2.datehour);
printf("\tMinute = %d.\n", dateinfo2.dateminute);
printf("\tSecond = %d.\n", dateinfo2.datesecond);
printf("\tNanosecond = %d.\n", dateinfo2.datensecond);
if (dateinfo2.dateyear != 1898 || dateinfo2.datensecond != 567000000)
set_failed();
}
#endif

dbclose(dbproc);
dbexit();

if (output_count < 2 || output_count > 3)
set_failed();

fprintf(stdout, "%s %s\n", __FILE__, (failed ? "failed!" : "OK"));
return failed ? 1 : 0;
}
2 changes: 2 additions & 0 deletions src/dblib/unittests/t0012.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ insert into #dblib0012 values ('Dec 25 1898 07:30:00:567PM')
go
SELECT dt FROM #dblib0012
go
SELECT CAST('Dec 25 1898 07:30:00:567PM' AS DATETIME2)
go

0 comments on commit 8bebc32

Please sign in to comment.