Commit 479b70db authored by merlinofchaos's avatar merlinofchaos

#239380: Database safe date handling by KarenS! This is a major improvement for PGSQL users!

parent 3f301ee7
...@@ -1380,17 +1380,16 @@ function views_ui_rearrange_form(&$form_state) { ...@@ -1380,17 +1380,16 @@ function views_ui_rearrange_form(&$form_state) {
$form[$id]['name'] = array( $form[$id]['name'] = array(
'#value' => $name, '#value' => $name,
); );
$form[$id]['removed'] = array(
'#type' => 'checkbox',
'#id' => 'views-removed-' . $id,
'#attributes' => array('class' => 'views-remove-checkbox'),
'#default_value' => 0,
);
} }
else { else {
$form[$id]['name'] = array('#value' => t('Broken field @id', $id)); $form[$id]['name'] = array('#value' => t('Broken field @id', array('@id' => $id)));
} }
$form[$id]['removed'] = array(
'#type' => 'checkbox',
'#id' => 'views-removed-' . $id,
'#attributes' => array('class' => 'views-remove-checkbox'),
'#default_value' => 0,
);
} }
// Add javascript settings that will be added via $.extend for tabledragging // Add javascript settings that will be added via $.extend for tabledragging
...@@ -1660,12 +1659,13 @@ function views_ui_config_item_form(&$form_state) { ...@@ -1660,12 +1659,13 @@ function views_ui_config_item_form(&$form_state) {
break; break;
} }
$relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
$relationship_handler->init($view, $relationship);
// ignore invalid/broken relationships. // ignore invalid/broken relationships.
if (empty($relationship_handler)) { if (empty($relationship_handler)) {
continue; continue;
} }
$relationship_handler->init($view, $relationship);
$relationship_options[$relationship['id']] = $relationship_handler->label(); $relationship_options[$relationship['id']] = $relationship_handler->label();
} }
......
...@@ -936,29 +936,26 @@ class views_handler_sort_date extends views_handler_sort { ...@@ -936,29 +936,26 @@ class views_handler_sort_date extends views_handler_sort {
* Called to add the sort to a query. * Called to add the sort to a query.
*/ */
function query() { function query() {
$timezone = views_get_timezone();
$timezone = ($timezone) ? sprintf('%+d', $timezone) : '';
$this->ensure_my_table(); $this->ensure_my_table();
switch($this->options['granularity']) { switch($this->options['granularity']) {
case 'second': case 'second':
default: default:
$this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']); $this->query->add_orderby($this->table_alias, "$this->table_alias.$this->real_field", $this->options['order']);
return; return;
case 'minute': case 'minute':
$formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field), '%Y%m%%d%H%i')"; $formula = views_date_sql_format('YmdHi', "$this->table_alias.$this->real_field");
break; break;
case 'hour': case 'hour':
$formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field), '%Y%m%%d%H')"; $formula = views_date_sql_format('YmdH', "$this->table_alias.$this->real_field");
break; break;
case 'day': case 'day':
$formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field $timezone), '%Y%m%%d')"; $formula = views_date_sql_format('Ymd', "$this->table_alias.$this->real_field");
break; break;
case 'month': case 'month':
$formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field $timezone), '%Y%m')"; $formula = views_date_sql_format('Ym', "$this->table_alias.$this->real_field");
break; break;
case 'year': case 'year':
$formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field $timezone), '%Y')"; $formula = views_date_sql_format('Y', "$this->table_alias.$this->real_field");
break; break;
} }
......
...@@ -164,7 +164,7 @@ class views_plugin_display extends views_object { ...@@ -164,7 +164,7 @@ class views_plugin_display extends views_object {
if (!isset($this->has_exposed)) { if (!isset($this->has_exposed)) {
foreach (array('field', 'filter') as $type) { foreach (array('field', 'filter') as $type) {
foreach ($this->view->$type as $key => $info) { foreach ($this->view->$type as $key => $info) {
if ($info['handler']->is_exposed()) { if (!empty($info['handler']) && $info['handler']->is_exposed()) {
// one is all we need; if we find it, return true. // one is all we need; if we find it, return true.
$this->has_exposed = TRUE; $this->has_exposed = TRUE;
return TRUE; return TRUE;
......
...@@ -886,8 +886,7 @@ class views_handler_argument_node_created_fulldate extends views_handler_argumen ...@@ -886,8 +886,7 @@ class views_handler_argument_node_created_fulldate extends views_handler_argumen
* Constructor implementation * Constructor implementation
*/ */
function construct() { function construct() {
$timezone = views_get_timezone(); $this->formula = views_date_sql_format('Ymd', "***table***.$this->real_field");
$this->formula = "DATE_FORMAT(FROM_UNIXTIME(***table***.$this->real_field+$timezone), '%Y%m%%d')";
$this->format = 'F j, Y'; $this->format = 'F j, Y';
} }
...@@ -917,8 +916,7 @@ class views_handler_argument_node_created_year extends views_handler_argument_fo ...@@ -917,8 +916,7 @@ class views_handler_argument_node_created_year extends views_handler_argument_fo
* Constructor implementation * Constructor implementation
*/ */
function construct() { function construct() {
$timezone = views_get_timezone(); $this->formula = views_date_sql_extract('YEAR', "***table***.$this->real_field");
$this->formula = "YEAR(FROM_UNIXTIME(***table***.$this->real_field+$timezone))";
} }
} }
...@@ -932,8 +930,7 @@ class views_handler_argument_node_created_year_month extends views_handler_argum ...@@ -932,8 +930,7 @@ class views_handler_argument_node_created_year_month extends views_handler_argum
* Constructor implementation * Constructor implementation
*/ */
function construct() { function construct() {
$timezone = views_get_timezone(); $this->formula = views_date_sql_format('Ym', "***table***.$this->real_field");
$this->formula = "DATE_FORMAT(FROM_UNIXTIME(***table***.$this->real_field+$timezone), '%Y%m')";
$this->format = 'F, Y'; $this->format = 'F, Y';
} }
...@@ -963,8 +960,7 @@ class views_handler_argument_node_created_month extends views_handler_argument_f ...@@ -963,8 +960,7 @@ class views_handler_argument_node_created_month extends views_handler_argument_f
* Constructor implementation * Constructor implementation
*/ */
function construct() { function construct() {
$timezone = views_get_timezone(); $this->formula = views_date_sql_extract('MONTH', "***table***.$this->real_field");
$this->formula = "MONTH(FROM_UNIXTIME(***table***.$this->real_field+$timezone))";
$this->format = 'F'; $this->format = 'F';
} }
...@@ -994,8 +990,7 @@ class views_handler_argument_node_created_week extends views_handler_argument_fo ...@@ -994,8 +990,7 @@ class views_handler_argument_node_created_week extends views_handler_argument_fo
* Constructor implementation * Constructor implementation
*/ */
function construct() { function construct() {
$timezone = views_get_timezone(); $this->formula = views_date_sql_extract('WEEK', "***table***.$this->real_field");
$this->formula = "WEEK(FROM_UNIXTIME(***table***.$this->real_field+$timezone), 3)";
} }
/** /**
......
...@@ -857,6 +857,166 @@ function views_get_timezone() { ...@@ -857,6 +857,166 @@ function views_get_timezone() {
return $timezone; return $timezone;
} }
/**
* Helper function to create cross-database SQL dates.
*
* @param $field
* The real table and field name, like 'tablename.fieldname'.
* @param $field_type
* The type of date field, 'int' or 'datetime'.
* @param $set_offset
* The name of a field that holds the timezone offset or a fixed timezone
* offset value. If not provided, the normal Drupal timezone handling
* will be used, i.e. $set_offset = 0 will make no timezone adjustment.
* @return
* An appropriate SQL string for the db type and field type.
*/
function views_date_sql_field($field, $field_type = 'int', $set_offset = NULL) {
$db_type = $GLOBALS['db_type'];
$offset = $set_offset !== NULL ? $set_offset : views_get_timezone();
switch ($db_type) {
case 'mysql':
case 'mysqli':
switch ($field_type) {
case 'int':
$field = "FROM_UNIXTIME($field)";
break;
case 'datetime':
break;
}
if (!empty($offset)) {
$field = "($field + INTERVAL $offset SECOND)";
}
return $field;
case 'pgsql':
switch ($field_type) {
case 'int':
$field = "$field::ABSTIME";
break;
case 'datetime':
break;
}
if (!empty($offset)) {
$field = "($field + 'INTERVAL $offset SECONDS')";
}
return $field;
}
}
/**
* Helper function to create cross-database SQL date formatting.
*
* @param $format
* A format string for the result, like 'Y-m-d H:i:s'.
* @param $field
* The real table and field name, like 'tablename.fieldname'.
* @param $field_type
* The type of date field, 'int' or 'datetime'.
* @param $set_offset
* The name of a field that holds the timezone offset or a fixed timezone
* offset value. If not provided, the normal Drupal timezone handling
* will be used, i.e. $set_offset = 0 will make no timezone adjustment.
* @return
* An appropriate SQL string for the db type and field type.
*/
function views_date_sql_format($format, $field, $field_type = 'int', $set_offset = NULL) {
$db_type = $GLOBALS['db_type'];
$field = views_date_sql_field($field, $field_type, $set_offset);
switch ($db_type) {
case 'mysql':
case 'mysqli':
$replace = array(
'Y' => '%Y',
'm' => '%m',
'd' => '%%d',
'H' => '%H',
'i' => '%i',
's' => '%s',
);
$format = str_replace($format, $replace);
return "DATE_FORMAT($field, $format)";
case 'pgsql':
$replace = array(
'Y' => 'YY',
'm' => 'MM',
'd' => 'DD',
'H' => 'HH24',
'i' => 'MI',
's' => 'SS',
);
$format = str_replace($format, $replace);
return "TO_CHAR($field, $format)";
}
}
/**
* Helper function to create cross-database SQL date extraction.
*
* @param $extract_type
* The type of value to extract from the date, like 'MONTH'.
* @param $field
* The real table and field name, like 'tablename.fieldname'.
* @param $field_type
* The type of date field, 'int' or 'datetime'.
* @param $set_offset
* The name of a field that holds the timezone offset or a fixed timezone
* offset value. If not provided, the normal Drupal timezone handling
* will be used, i.e. $set_offset = 0 will make no timezone adjustment.
* @return
* An appropriate SQL string for the db type and field type.
*/
function views_date_sql_extract($extract_type, $field, $field_type = 'int', $set_offset = NULL) {
$db_type = $GLOBALS['db_type'];
$field = views_date_sql_field($field, $field_type, $set_offset);
// Note there is no space after FROM to avoid db_rewrite problems
// see http://drupal.org/node/79904.
switch ($extract_type) {
case('DATE'):
return $field;
case('YEAR'):
return "EXTRACT(YEAR FROM($field))";
case('MONTH'):
return "EXTRACT(MONTH FROM($field))";
case('DAY'):
return "EXTRACT(DAY FROM($field))";
case('HOUR'):
return "EXTRACT(HOUR FROM($field))";
case('MINUTE'):
return "EXTRACT(MINUTE FROM($field))";
case('SECOND'):
return "EXTRACT(SECOND FROM($field))";
case('WEEK'): // ISO week number for date
switch ($db_type) {
case('mysql'):
case('mysqli'):
// WEEK using arg 3 in mysql should return the same value as postgres EXTRACT
return "WEEK($field, 3)";
case('pgsql'):
return "EXTRACT(WEEK FROM($field))";
}
case('DOW'):
switch ($db_type) {
case('mysql'):
case('mysqli'):
// mysql returns 1 for Sunday through 7 for Saturday
// php date functions and postgres use 0 for Sunday and 6 for Saturday
return "INTEGER(DAYOFWEEK($field) - 1)";
case('pgsql'):
return "EXTRACT(DOW FROM($field))";
}
case('DOY'):
switch ($db_type) {
case('mysql'):
case('mysqli'):
return "DAYOFYEAR($field)";
case('pgsql'):
return "EXTRACT(DOY FROM($field))";
}
}
}
/** /**
* Form builder for the exposed widgets form. * Form builder for the exposed widgets form.
* *
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment