Use the same buffer for separate DATE and TIME - mysql

I am using the MySQL C api along with prepared statements. When issuing a INSERT query with a TIME field the result is in HHH:MM:SS format, where the hours are the amount of hours elapsed this month. For instance if the date is 2015-02-21, and the time is 21:30:00 the time would be displayed as 525:30:00 but I want to use the HH:MM:SS format instead (e.g 21:30:00), which would be the actual time of the day.
sbind[3].buffer_type=MYSQL_TYPE_DATE;
sbind[3].buffer= (char *)&ts; // Pointer to a MYSQL_TIME data structure
sbind[3].is_null= 0;
sbind[3].length= 0;
sbind[4] = sbind[3];
sbind[4].buffer_type=MYSQL_TYPE_TIME;
mysql_stmt_bind_param(stmt, sbind); // sbind is an array of MYSQL_BIND structures
ts.year= 1900+tm_info->tm_year; // tm_info is a pointer to a tm structure
ts.month= 1+tm_info->tm_mon;
ts.day= tm_info->tm_mday;
ts.hour= tm_info->tm_hour;
ts.minute= tm_info->tm_min;
ts.second= tm_info->tm_sec;
This code will prepare the date field as yyyy-mm-dd and fill it with the date in tm_info. Likewise it will do the same thing for the time field but in the HHH:MM:SS format.
A unfashionable way which works is to use a separate MYSQL_TIME structure for the time, but I aim for a more elegant way to handle this.
(EDIT: Here I have included the relevant client side code
MYSQL_TIME ts;
MYSQL_STMT *stmt;
MYSQL_BIND sbind[2];
...
char query[QUERY_BUFFER_SIZE];
strcpy(query, "INSERT INTO `mytable` (date,time) VALUES(?,?)");
if(mysql_stmt_prepare(stmt, query, strlen(query))){
return mysql_stmt_errno(stmt);
}
...
time_t rawtime;
time(&rawtime); // get current time
struct tm *tm_info = localtime ( &rawtime );
...
memset(sbind,0,sizeof(sbind));
sbind[0].buffer_type=MYSQL_TYPE_DATE;
sbind[0].buffer= (char *)&ts; // Pointer to a MYSQL_TIME data structure
sbind[0].is_null= 0;
sbind[0].length= 0;
sbind[1] = sbind[0];
sbind[1].buffer_type=MYSQL_TYPE_TIME;
mysql_stmt_bind_param(stmt, sbind); // sbind is an array of MYSQL_BIND structures
ts.year= 1900+tm_info->tm_year; // tm_info is a pointer to a tm structure
ts.month= 1+tm_info->tm_mon;
ts.day= tm_info->tm_mday;
ts.hour= tm_info->tm_hour;
ts.minute= tm_info->tm_min;
ts.second= tm_info->tm_sec;
if(mysql_stmt_execute(stmt)){
return mysql_stmt_errno(stmt);
}
This assumes mysql is a valid connection. The table mytable in this case only contains a DATE type and a TIME type.
)

That's the natural representation for the TIME type - it, as the name suggests, only holds time, and this is the natural way to express time larger than a day. It does, as the documentation suggests, use HH:MM:SS for smaller values.
Since TIME does not care about shenanigans like leap seconds, to exclude full days, just take tm_hour%24. But, to allow for shenanigans like DST transitions, you have nothing to do but add the TIME to the starting point of the specific month and do DATETIME arithmetic with the stock functions.
#c45602234:
Trying to outsmart libmysql FAILED (mysql-connector-c-6.1.5/libmysql/libmysql.c:1964):
static void store_param_date(NET *net, MYSQL_BIND *param)
{
MYSQL_TIME tm= *((MYSQL_TIME *) param->buffer);
tm.hour= tm.minute= tm.second= tm.second_part= 0;
net_store_datetime(net, &tm);
}
As you can see, it always uses up the entire structure (apparently, so that relevant functions always work as expected).

Related

Laravel 4.1 - display time format from mysql column TIME

I have a column in mysql database named time_start which type is TIME.
I am trying to format the displayed time in my view from H:i:s to simple H:i, so instead of 20:00:00 i will get 20:00.
Firstly i thought i can use format() method, but it's supposed to be used with timestamps, so of course i get error Call to a member function format() on a non-object.
I'm sure it's a simple question, but i can't solve this.
-EDIT-
Forgt to mention. I am working with a many to many relationship and i'm calling my data like:
$schedule->time_start
Here i would like to show the time in H:i format, not H:i:s.
Have you tried an accessor method? I.e. in the Schedule model,
/**
* Return a truncated version of the timestamp.
* #param $value original value of attribute
* #return string truncated value
*/
public function getTimeStartAttribute($value)
{
// Input is HH:MM:SS
return substr($value, 0, 5);
// Output is HH:MM
}
Then $schedule->time_start ought to return the time in HH:MM format.

C - How to convert time_t to tm?

I have a variable which using time_t data type. I want to convert this type into "YYYY-MM-DD HH:MM:SS". I just know if it's only works in localtime() example:
char buff[20];
time_t now = time(NULL);
strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
any suggestion how to convert it? because I have the time which always increased every minute, not the fixed one like the localtime(). I need this conversion for matching with datetime type in MySQL database.
The functions gmtime and localtime (for UTC and local time respectively) will turn an arbitrary time_t into a struct tm with individual fields for year, month and so on.
You can then just use strftime as you have, or sprintf to create strings from them, such as with:
char buff[11];
sprintf (buff, "%04d-%02d-%02d",
mytm.tm_year + 1900,
mytm.tm_mon + 1,
mytm.tm_mday);

How to display date using C++?

How can I display the date using the function "MessageBox"?
Here is a link for several different ways to get the date and time:
Date & Time
Copied from site above:
Definition (from windows):
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
Implementation:
SYSTEMTIME st;
GetSystemTime(&st);
// You format how you want
DateTime dateTime = DateTime::Now;
MessageBox::Show(dateTime.ToString());
Other ToXString() functions can be found here
For example like this (I assumed you asked about native Windows API):
// Get current time
SYSTEMTIME now;
GetLocalTime(&now);
// Format the date using the default user language
TCHAR buffer[1024];
GetDateFormat(
MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT),
0,
&now,
NULL,
buffer,
1024
);
// Show it in a message box
MessageBox(HWND_DESKTOP, buffer, _T("Today"), MB_OK);
It's also possible to ask GetDateFormat to calculate the buffer length required to store the output. To do that pass NULL and 0 as last two parameters:
int length = GetDateFormat(
MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT),
0,
&now,
NULL,
NULL,
0
);

How to to create unique random integer ID for primary key for table?

I was wondering if anybody knew a good way to create a unique random integer id for a primary key for a table. I'm using MySQL. The value has to be integer.
In response to: "Because I want to use that value to Encode to Base62 and then use that for an id in a url. If i auto increment, it might be obvious to the user how the url id is generated."
If security is your aim then using Base62, even with a "randomly" generated number won't help.
A better option would:
Do not re-invent the wheel -- use AUTO_INCREMENT
Then use a cryptographic hash function + a randomly generated string (hidden in the db for that particular url) to generate the final "unique id for that url"
If your're open to suggestions and you can implement it, use UUIDs.
MySQL's UUID() function will return a 36 chars value which can be used for ID.
If you want to use integer, still, I think you need to create a function getRandID() that you will use in the INSERT statement. This function needs to use random + check of existing ids to return one that is not used before.
Check RAND() function for MySQL.
How you generate the unique_ids is a useful question - but you seem to be making a counter productive assumption about when you generate them!
My point is that you do not need to generate these unique id's at the time of creating your rows, because they are essentially independent of the data being inserted.
What I do is pre-generate unique id's for future use, that way I can take my own sweet time and absolutely guarantee they are unique, and there's no processing to be done at the time of the insert.
For example I have an orders table with order_id in it. This id is generated on the fly when the user enters the order, incrementally 1,2,3 etc forever. The user does not need to see this internal id.
Then I have another table - unique_ids with (order_id, unique_id). I have a routine that runs every night which pre-loads this table with enough unique_id rows to more than cover the orders that might be inserted in the next 24 hours. (If I ever get 10000 orders in one day I'll have a problem - but that would be a good problem to have!)
This approach guarantees uniqueness and takes any processing load away from the insert transaction and into the batch routine, where it does not affect the user.
How about this approach (PHP and MySQL):
Short
Generate random number for user_id (UNIQUE)
Insert row with generated number as user_id
If inserted row count equal to 0, go to point 1
Looks heavy? Continue to read.
Long:
Table:
users (user_id int UNIQUE)
Code:
<?php
// values stored in configuration
$min = 1;
$max = 1000000;
$numberOfLoops = 0;
do {
$randomNumber = rand($min, $max);
// the very insert
$insertedRows = insert_to_table(
'INSERT INTO foo_table (user_id) VALUES (:number)',
array(
':number' => $randomNumber
));
$numberOfLoops++;
// the magic
if (!isset($reported) && $numberOfLoops / 10 > 0.5) {
/**
* We can assume that at least 50% of numbers
* are already in use, so increment values of
* $min and $max in configuration.
*/
report_this_fact();
$reported = true;
} while ($insertedRows < 1);
All values ($min, $max, 0.5) are just for explanation and they have no statistical meaning.
Functions insert_to_table and report_this_fact are not build in PHP. The are also as numbers just for clarify of explanation purposes.
You can use an AUTO_INCREMENT for your table, but give the users the encrypted version:
encrypted_id: SELECT HEX(AES_ENCRYPT(id, 'my-private-key'));
id: SELECT AES_DECRYPT(UNHEX(encrypted_id), 'my-private-key');
my way, for both 32bit and 64bit platform. result is 64bit
function hexstr2decstr($hexstr){
$bigint = gmp_init($hexstr, 16);
$bigint_string = gmp_strval($bigint);
return $bigint_string;
}
function generate_64bitid(){
return substr(md5(uniqid(rand(), true)), 16, 16);
}
function dbGetUniqueXXXId(){
for($i = 0; $i < 10; $i++){
$decstr = hexstr2decstr(generate_64bitid());
//check duplicate for mysql.tablexxx
if($dup == false){
return $decstr;
}
}
return false;
}
AUTO_INCREMENT is going to be your best bet for this.
Here are some examples.
If you need to you can adjust where the increment value starts (by default it's 1).
There is an AUTO_INCREMENT feature. I would use that.
See here more examples.

MySQL C API using results

I am using the MySQL C API to query the database and I have the results stored in MYSQL_ROW types. I am able to print the results to the console with
printf("%s", row[0]);
however, according to the MySQL C API documentation, I cannot use them as null-terminated strings.
At the bottom of the function overview, they say I can "extract" the information with mysql_store_result() or mysql_use_result(). However, I am still confused as to how this is done.
Ideally, I want to use the results as a string so I can do stuff like strcmp, but otherwise I definitely need to use the information somehow with those two functions.
Can somebody show me an example of how to do this?
Basically, you call mysql_store_result() or mysql_use_result() to access the result set, the former loads all the rows into memory on the client side, the latter accesses rows one at a time from the server. If you use mysql_use_result(), you need to call mysql_fetch_row() to access each row until the function returns NULL. Each successful call to mysql_fetch_row() will return a MYSQL_ROW which you can use to access the individual field values.
Since the fields are not nul-terminated, you need to use mysql_fetch_lengths() to get the lengths of each of the fields so that you can copy them somewhere else via memcpy, etc.
Since the field values are not nul-terminated you will need to add your own NUL character when you make the copy if you want to use it as a string. Be aware that the field values may contain binary data, so if you do treat it as a string, functions that expect a C string will stop processing data if it encounters a nul-character in the data.
Here is an example from the documentation that should help you put all this together:
MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
unsigned long *lengths;
lengths = mysql_fetch_lengths(result);
for(i = 0; i < num_fields; i++)
{
printf("[%.*s] ", (int) lengths[i],
row[i] ? row[i] : "NULL");
}
printf("\n");
}