Index: components/time.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/time.inc,v
retrieving revision 1.24.2.2
diff -u -r1.24.2.2 time.inc
--- components/time.inc	8 Mar 2010 01:04:08 -0000	1.24.2.2
+++ components/time.inc	14 Mar 2010 04:00:11 -0000
@@ -173,17 +173,17 @@
   }
 
   if (isset($value)) {
-    $element['minute']['#default_value'] = $value[1];
+    $element['minute']['#default_value'] = $value['minute'];
   
     // Match the hourly data to the hour format.
-    if ($value[1]) {
-      $timestamp = strtotime($value[0] . ':' . $value[1] . (isset($value[2]) ? $value[2] : ''));
+    if ($value['hour']) {
+      $timestamp = strtotime($value['hour'] . ':' . $value['minute'] . (isset($value['ampm']) ? $value['ampm'] : ''));
       if ($component['extra']['hourformat'] == '24-hour') {
         $element['hour']['#default_value'] = date('H', $timestamp);
       }
       else {
         $element['hour']['#default_value'] = date('g', $timestamp);
-        $element['ampm']['#default_value'] = $value[2];
+        $element['ampm']['#default_value'] = $value['ampm'];
       }
     }
   }
@@ -217,9 +217,9 @@
  */
 function _webform_display_time($component, $value, $format = 'html') {
   $value = array(
-    'hour' => isset($value[0]) ? $value[0] : NULL,
-    'minute' => isset($value[1]) ? $value[1] : NULL,
-    'ampm' => isset($value[2]) ? $value[2] : NULL,
+    'hour' => isset($value['hour']) ? $value['hour'] : NULL,
+    'minute' => isset($value['minute']) ? $value['minute'] : NULL,
+    'ampm' => isset($value['ampm']) ? $value['ampm'] : NULL,
   );
 
   return array(
@@ -261,22 +261,24 @@
     ' FROM {webform_submitted_data} ' .
     ' WHERE nid = %d ' .
     ' AND  cid = %d ' . $sidfilter .
-    ' ORDER BY sid,no ASC ';
+    ' ORDER BY sid ASC ';
 
   $result = db_query($query, array_merge(array($component['nid'], $component['cid']), $sids));
 
   // Build an array of timestamps from entered values.
   $timestamps = array();
   $submissions = 1;
+  $current_sid = 0;
   while ($row = db_fetch_array($result)) {
-    if ($row['no'] == '0') {
+    if ($current_sid != $row['sid'])
+    if ($row['no'] == 'hour') {
       $submissions++;
       $hour = $row['data'];
       if ($row = db_fetch_array($result)) {
-        if ($row['no'] == '1') {
+        if ($row['no'] == 'minute') {
           $minute = $row['data'];
           if ($row = db_fetch_array($result)) {
-            if ($row['no'] == '2') {
+            if ($row['no'] == 'ampm') {
               $ampm = $row['data'];
               // Build the full timestamp.
               if (drupal_strlen($hour) > 0 && drupal_strlen($minute) > 0 ) {
@@ -305,8 +307,8 @@
  * Implementation of _webform_table_component().
  */
 function _webform_table_time($component, $value) {
-  if (drupal_strlen($value[0]) > 0 && drupal_strlen($value[1]) > 0) {
-    $timestamp = strtotime($value[0] . ':' . $value[1] . $value[2]);
+  if (drupal_strlen($value['hour']) > 0 && drupal_strlen($value['minute']) > 0) {
+    $timestamp = strtotime($value['hour'] . ':' . $value['minute'] . (isset($value['ampm']) ? $value['ampm'] : ''));
     if ($component['extra']['hourformat'] == '24-hour') {
       return check_plain(date('H:i', $timestamp));
     }
@@ -334,8 +336,8 @@
  * Implementation of _webform_csv_data_component().
  */
 function _webform_csv_data_time($component, $export_options, $value) {
-  if (drupal_strlen($value[0]) > 0 && drupal_strlen($value[1]) > 0) {
-    $timestamp = strtotime($value[0] . ':' . $value[1] . $value[2]);
+  if (drupal_strlen($value['hour']) > 0 && drupal_strlen($value['minute']) > 0) {
+    $timestamp = strtotime($value['hour'] . ':' . $value['minute'] . (isset($value['ampm']) ? $value['ampm'] : ''));
     if ($component['extra']['hourformat'] == '24-hour') {
       return date('H:i', $timestamp);
     }
Index: components/date.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/date.inc,v
retrieving revision 1.29.2.2
diff -u -r1.29.2.2 date.inc
--- components/date.inc	8 Mar 2010 01:04:08 -0000	1.29.2.2
+++ components/date.inc	14 Mar 2010 04:00:11 -0000
@@ -124,11 +124,7 @@
   );
 
   if (isset($value)) {
-    $element['#default_value'] = array(
-      'month' => $value[0],
-      'day' => $value[1],
-      'year' => $value[2],
-    );
+    $element['#default_value'] = $value;
   }
 
   return $element;
@@ -261,7 +257,7 @@
 function _webform_submit_date($component, $value) {
   // Webform stores dates in month/day/year rows.
   // Ensure consistency when using international date formats.
-  return array($value['month'], $value['day'], $value['year']);
+  return array('month' => $value['month'], 'day' => $value['day'], 'year' => $value['year']);
 }
 
 /**
@@ -269,9 +265,9 @@
  */
 function _webform_display_date($component, $value, $format = 'html') {
   $value = array(
-    'month' => isset($value[0]) ? $value[0] : NULL,
-    'day' => isset($value[1]) ? $value[1] : NULL,
-    'year' => isset($value[2]) ? $value[2] : NULL,
+    'month' => isset($value['month']) ? $value['month'] : NULL,
+    'day' => isset($value['day']) ? $value['day'] : NULL,
+    'year' => isset($value['year']) ? $value['year'] : NULL,
   );
 
   return array(
@@ -310,7 +306,7 @@
     ' FROM {webform_submitted_data} ' .
     ' WHERE nid = %d ' .
     ' AND  cid = %d ' . $sidfilter .
-    ' ORDER BY sid,no ASC ';
+    ' ORDER BY sid ASC ';
 
   $result = db_query($query, array_merge(array($component['nid'], $component['cid']), $sids));
 
@@ -356,8 +352,8 @@
  * Implementation of _webform_table_component().
  */
 function _webform_table_date($component, $value) {
-  if (drupal_strlen($value[0]) > 0 && drupal_strlen($value[1]) > 0 && drupal_strlen($value[2]) > 0) {
-    $timestamp = webform_strtotime($value[0] . '/' . $value[1] . '/' . $value[2]);
+  if (drupal_strlen($value['month']) > 0 && drupal_strlen($value['day']) > 0 && drupal_strlen($value['year']) > 0) {
+    $timestamp = webform_strtotime($value['month'] . '/' . $value['day'] . '/' . $value['year']);
     $format = webform_date_format('short');
     return format_date($timestamp, 'custom', $format, 0);
   }
@@ -381,8 +377,8 @@
  * Implementation of _webform_csv_data_component().
  */
 function _webform_csv_data_date($component, $export_options, $value) {
-  if (drupal_strlen($value[0]) > 0 && drupal_strlen($value[1]) > 0 && drupal_strlen($value[2]) > 0) {
-    $timestamp = webform_strtotime($value[0] . '/' . $value[1] . '/' . $value[2]);
+  if (drupal_strlen($value['month']) > 0 && drupal_strlen($value['day']) > 0 && drupal_strlen($value['year']) > 0) {
+    $timestamp = webform_strtotime($value['month'] . '/' . $value['day'] . '/' . $value['year']);
     $format = webform_date_format('short');
     return format_date($timestamp, 'custom', $format, 0);
   }
Index: components/select.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/select.inc,v
retrieving revision 1.39.2.4
diff -u -r1.39.2.4 select.inc
--- components/select.inc	11 Mar 2010 01:40:15 -0000	1.39.2.4
+++ components/select.inc	14 Mar 2010 04:00:11 -0000
@@ -46,11 +46,12 @@
  */
 function _webform_edit_select($component) {
   $form = array();
+
   $form['extra']['items'] = array(
     '#type' => 'textarea',
     '#title' => t('Options'),
     '#default_value' => $component['extra']['items'],
-    '#description' => t('A list of selectable options. One option per line. Key-value pairs may be entered seperated by pipes, such as "safe_key|Some readable option". Option groups for lists and menus may be specified with &lt;Group Name&gt;. &lt;&gt; can be used to insert items at the root of the menu after specifying a group.') . theme('webform_token_help'),
+    '#description' => t('<strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Only alphanumeric characters and underscores are allowed as a key. One option per line. Option groups may be specified with &lt;Group Name&gt;. &lt;&gt; can be used to insert items at the root of the menu after specifying a group.') . theme('webform_token_help'),
     '#cols' => 60,
     '#rows' => 5,
     '#weight' => -2,
@@ -69,21 +70,18 @@
   $form['extra']['multiple'] = array(
     '#type' => 'checkbox',
     '#title' => t('Multiple'),
-    '#return_value' => 'Y',
     '#default_value' => $component['extra']['multiple'],
     '#description' => t('Check this option if the user should be allowed to choose multiple values.'),
   );
   $form['extra']['aslist'] = array(
     '#type' => 'checkbox',
     '#title' => t('Listbox'),
-    '#return_value' => 'Y',
     '#default_value' => $component['extra']['aslist'],
     '#description' => t('Check this option if you want the select component to be of listbox type instead of radiobuttons or checkboxes.'),
   );
   $form['extra']['other_option'] = array(
     '#type' => 'checkbox',
     '#title' => t('Allow "Other..." option'),
-    '#return_value' => 'Y',
     '#default_value' => $component['extra']['other_option'],
     '#description' => t('Check this option if you want to allow users to enter an option not on the list.'),
     '#access' => module_exists('select_or_other'),
@@ -109,14 +107,15 @@
 /**
  * Element validation callback. Ensure keys are not duplicated.
  */
-function _webform_edit_validate_select($element, $form_state) {
-  // TODO: Validate e-mail addresses when used as keys?\
-
-  // Check for duplicate key values to prevent unexpected data loss.
+function _webform_edit_validate_select($element, &$form_state) {
+  // Check for duplicate key values to prevent unexpected data loss. Require
+  // all options to include a safe_key.
   if (!empty($element['#value'])) {
-    $lines = explode("\n", $element['#value']);
+    $lines = explode("\n", trim($element['#value']));
     $existing_keys = array();
     $duplicate_keys = array();
+    $missing_keys = array();
+    $long_keys = array();
     $group = '';
     foreach ($lines as $line) {
       $matches = array();
@@ -125,11 +124,14 @@
         $group = $matches[1];
         $key = NULL; // No need to store group names.
       }
-      elseif (preg_match('/^([^|]+)\|(.*)$/', $line, $matches)) {
+      elseif (preg_match('/^([^|]*)\|(.*)$/', $line, $matches)) {
         $key = $matches[1];
+        if (strlen($key) > 128) {
+          $long_keys[] = $key;
+        }
       }
       else {
-        $key = $line;
+        $missing_keys[] = $line;
       }
 
       if (isset($key)) {
@@ -142,6 +144,14 @@
       }
     }
 
+    if (!empty($missing_keys)) {
+      form_error($element, t('Every option must have a key specified. Specify each option as "safe_key|Some readable option".'));
+    }
+
+    if (!empty($long_keys)) {
+      form_error($element, t('Option keys must be less than 128 characters. The following keys exceed this limit:') . theme('item_list', $long_keys));
+    }
+
     if (!empty($duplicate_keys)) {
       form_error($element, t('Options within the select list must be unique. The following keys have been used multiple times:') . theme('item_list', $duplicate_keys));
     }
@@ -164,13 +174,13 @@
 
   // Convert the user-entered options list into an array.
   $default_value = $filter ? _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE) : $component['value'];
-  $options = _webform_select_options($component['extra']['items'], $component['extra']['aslist'] !== 'Y', $filter);
+  $options = _webform_select_options($component['extra']['items'], !$component['extra']['aslist'], $filter);
 
   if ($component['extra']['optrand']) {
     _webform_shuffle_options($options);
   }
 
-  if ($component['extra']['aslist'] === 'Y' && $component['extra']['multiple'] !== 'Y' && !($component['mandatory'] && !empty($component['value']))) {
+  if ($component['extra']['aslist'] && !$component['extra']['multiple'] && !($component['mandatory'] && !empty($component['value']))) {
     $options = array('' => t('select...')) + $options;
   }
 
@@ -179,7 +189,7 @@
 
   // Set the default value.
   if (isset($value)) {
-    if ($component['extra']['multiple'] === 'Y') {
+    if ($component['extra']['multiple']) {
       // Set the value as an array.
       $element['#default_value'] = array();
       foreach ((array) $value as $key => $option_value) {
@@ -196,7 +206,7 @@
   }
   elseif ($default_value != '') {
     // Convert default value to a list if necessary.
-    if ($component['extra']['multiple'] === 'Y') {
+    if ($component['extra']['multiple']) {
       $varray = array_filter(explode(',', $default_value));
       foreach ($varray as $key => $v) {
         $element['#default_value'][] = $v;
@@ -206,17 +216,17 @@
       $element['#default_value'] = $default_value;
     }
   }
-  elseif ($component['extra']['multiple'] === 'Y') {
+  elseif ($component['extra']['multiple']) {
     $element['#default_value'] = array();
   }
 
-  if ($component['extra']['other_option'] === 'Y' && module_exists('select_or_other')) {
+  if ($component['extra']['other_option'] && module_exists('select_or_other')) {
     // Set display as a select list:
     $element['#type'] = 'select_or_other';
     $element['#other'] = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
     $element['#other_unknown_defaults'] = 'other';
     $element['#other_delimiter'] = ', ';
-    if ($component['extra']['multiple'] === 'Y') {
+    if ($component['extra']['multiple']) {
       $element['#multiple'] = TRUE;
       $element['#select_type'] = 'checkboxes';
     }
@@ -224,19 +234,19 @@
       $element['#multiple'] = FALSE;
       $element['#select_type'] = 'radios';
     }
-    if ($component['extra']['aslist'] === 'Y') {
+    if ($component['extra']['aslist']) {
       $element['#select_type'] = 'select';
     }
   }
-  elseif ($component['extra']['aslist'] === 'Y') {
+  elseif ($component['extra']['aslist']) {
     // Set display as a select list:
     $element['#type'] = 'select';
-    if ($component['extra']['multiple'] === 'Y') {
+    if ($component['extra']['multiple']) {
       $element['#multiple'] = TRUE;
     }
   }
   else {
-    if ($component['extra']['multiple'] === 'Y') {
+    if ($component['extra']['multiple']) {
       // Set display as a checkbox set.
       $element['#type'] = 'checkboxes';
       // Drupal 6 hack to properly render on multipage forms.
@@ -327,34 +337,31 @@
 function _webform_submit_select($component, $value) {
   $options = drupal_map_assoc(array_flip(_webform_select_options($component['extra']['items'], TRUE)));
 
+  $return = NULL;
   if (is_array($value)) {
+    $return = array();
     foreach ($value as $key => $option_value) {
       // Handle options that are specified options.
       if ($option_value !== '' && isset($options[$key])) {
         // Checkboxes submit an *integer* value of 0 when not checked.
-        if ($option_value === 0 && $options[$key] != '0' && $component['extra']['aslist'] !== 'Y' && $component['extra']['multiple'] === 'Y') {
+        if ($option_value === 0 && $options[$key] !== '0' && !$component['extra']['aslist'] && $component['extra']['multiple']) {
           unset($value[$key]);
         }
         else {
-          $value[$key] = $options[$key];
+          $return[] = $key;
         }
       }
       // Handle options that are added through the "other" field.
-      elseif ($component['extra']['other_option'] === 'Y' && module_exists('select_or_other')) {
-        $value[$key] = $option_value;
+      elseif ($component['extra']['other_option'] && module_exists('select_or_other')) {
+        $return[] = $option_value;
       }
-      else {
-        unset($value[$key]);
-      }
-    }
-
-    // Always save at least something, even if it's an empty single value.
-    if (empty($value)) {
-      $value[0] = '';
     }
   }
+  elseif (is_string($value)) {
+    $return = $value;
+  }
 
-  return $value;
+  return $return;
 }
 
 /**
@@ -455,7 +462,7 @@
     }
 
     // Add a row for any unknown or user-entered values.
-    if ($component['extra']['other_option'] === 'Y') {
+    if ($component['extra']['other_option']) {
       $full_count = db_result(db_query($count_query, array_merge(array($component['nid'], $component['cid']), $sids)));
       $other_count = $full_count - $normal_count;
       $display_option = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
@@ -502,7 +509,7 @@
     $headers[0][] = '';
     $headers[1][] = $component['name'];
     $items = _webform_select_options($component['extra']['items'], TRUE);
-    if ($component['extra']['other_option'] === 'Y') {
+    if ($component['extra']['other_option']) {
       $other_label = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
       $items[$other_label] = $other_label;
     }
@@ -545,7 +552,7 @@
     }
 
     // Any remaining items in the $value array will be user-added options.
-    if ($component['extra']['other_option'] === 'Y') {
+    if ($component['extra']['other_option']) {
       $return[] = count($value) ? implode(',', $value) : '';
     }
   }
Index: components/grid.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/grid.inc,v
retrieving revision 1.14.2.1
diff -u -r1.14.2.1 grid.inc
--- components/grid.inc	3 Mar 2010 02:51:31 -0000	1.14.2.1
+++ components/grid.inc	14 Mar 2010 04:00:11 -0000
@@ -54,21 +54,23 @@
     '#type' => 'textarea',
     '#title' => t('Options'),
     '#default_value' => $component['extra']['options'],
-    '#description' => t('Options to select across the top. One option per line. Key-value pairs may be entered seperated by pipes. i.e. safe_key|Some readable option') . theme('webform_token_help'),
+    '#description' => t('Options to select across the top. One option per line. Key-value pairs must be entered separated by pipes. i.e. safe_key|Some readable option') . theme('webform_token_help'),
     '#cols' => 60,
     '#rows' => 5,
     '#weight' => -3,
     '#required' => TRUE,
+    '#element_validate' => array('_webform_edit_validate_select'),
   );
   $form['extra']['questions'] = array(
     '#type' => 'textarea',
     '#title' => t('Questions'),
     '#default_value' => $component['extra']['questions'],
-    '#description' => t('Questions list down the left side. One question per line.') . theme('webform_token_help'),
+    '#description' => t('Questions list down the left side. One question per line. Key-value pairs must be entered separated by pipes. i.e safe_key|Some readable option') . theme('webform_token_help'),
     '#cols' => 60,
     '#rows' => 5,
     '#weight' => -2,
     '#required' => TRUE,
+    '#element_validate' => array('_webform_edit_validate_select'),
   );
   $form['display']['optrand'] = array(
     '#type' => 'checkbox',
@@ -99,18 +101,20 @@
     '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
   );
 
-  $questions = _webform_grid_options($component['extra']['questions']);
-  $options = _webform_grid_options($component['extra']['options']);
+  $questions = _webform_select_options($component['extra']['questions'], TRUE);
+  $options = _webform_select_options($component['extra']['options'], TRUE);
 
   if ($component['extra']['optrand']) {
     _webform_shuffle_options($options);
   }
 
-  $delta = 0;
-  foreach ($questions as $question) {
-    $delta++;
+  if ($component['extra']['qrand']) {
+    _webform_shuffle_options($questions);
+  }
+
+  foreach ($questions as $key => $question) {
     if ($question != '') {
-      $element['q' . $delta] = array(
+      $element[$key] = array(
         '#title'         => $question,
         '#required'      => $component['mandatory'],
         '#options'       => $options,
@@ -122,21 +126,9 @@
   }
 
   if (isset($value)) {
-    $cid = 0;
     foreach (element_children($element) as $key) {
-      $element[$key]['#default_value'] = $value[$cid++];
-    }
-  }
-
-  // Shuffle questions if needed.
-  if ($component['extra']['qrand']) {
-    $aux = array();
-    $keys = element_children($element);
-    shuffle($keys);
-    foreach ($keys as $key) {
-      $aux[$key] = array();
+      $element[$key]['#default_value'] = isset($value[$key]) ? $value[$key] : NULL;
     }
-    $element = array_merge($aux, $element);
   }
 
   return $element;
@@ -146,8 +138,8 @@
  * Implementation of _webform_display_component().
  */
 function _webform_display_grid($component, $value, $format = 'html') {
-  $questions = _webform_grid_options($component['extra']['questions']);
-  $options = _webform_grid_options($component['extra']['options']);
+  $questions = _webform_select_options($component['extra']['questions'], TRUE);
+  $options = _webform_select_options($component['extra']['options'], TRUE);
 
   $element = array(
     '#title' => $component['name'],
@@ -218,31 +210,12 @@
 }
 
 /**
- * Implementation of _webform_submit_component().
- */
-function _webform_submit_grid($component, $value) {
-  $options = drupal_map_assoc(array_flip(_webform_grid_options($component['extra']['options'])));
-  $questions = _webform_grid_options($component['extra']['questions']);
-
-  // Put the form in the original option order before saving.
-  // Return the final data with the quotes back in place.
-  $ordered_value = array();
-  $delta = 0;
-  foreach ($questions as $safe_question => $question) {
-    $delta++;
-    $ordered_value['q' . $delta] = isset($value['q' . $delta]) ? $value['q' . $delta] : '';
-  }
-
-  return $ordered_value;
-}
-
-/**
  * Implementation of _webform_analysis_component().
  */
 function _webform_analysis_grid($component, $sids = array()) {
   // Generate the list of options and questions.
-  $options = _webform_grid_options($component['extra']['options']);
-  $questions = array_values(_webform_grid_options($component['extra']['questions']));
+  $options = _webform_select_options($component['extra']['options'], TRUE);
+  $questions = _webform_select_options($component['extra']['questions'], TRUE);
 
   // Generate a lookup table of results.
   $placeholders = count($sids) ? array_fill(0, count($sids), "'%s'") : array();
@@ -286,7 +259,7 @@
  * Implementation of _webform_table_component().
  */
 function _webform_table_grid($component, $value) {
-  $questions = array_values(_webform_grid_options($component['extra']['questions']));
+  $questions = _webform_select_options($component['extra']['questions'], TRUE);
   $output = '';
   // Set the value as a single string.
   if (is_array($value)) {
@@ -309,7 +282,7 @@
   $header = array();
   $header[0] = array('');
   $header[1] = array($component['name']);
-  $items = _webform_grid_options($component['extra']['questions']);
+  $items = _webform_select_options($component['extra']['questions'], TRUE);
   $count = 0;
   foreach ($items as $key => $item) {
     // Empty column per sub-field in main header.
@@ -329,10 +302,10 @@
  * Implementation of _webform_csv_data_component().
  */
 function _webform_csv_data_grid($component, $export_options, $value) {
-  $questions = array_keys(_webform_grid_options($component['extra']['questions']));
+  $questions = _webform_select_options($component['extra']['questions'], TRUE);
   $return = array();
   foreach ($questions as $key => $question) {
-    $return[] = isset($value[$key]) ? $value[$key] : '';
+    $return[] = isset($value[$key]) ? $question : '';
   }
   return $return;
 }
@@ -367,22 +340,3 @@
   $option_count = count($header) - 1;
   return theme('form_element', $element, theme('table', $header, $rows, array('class' => 'webform-grid webform-grid-' . $option_count)));
 }
-
-/**
- * Utility function to convert user-entered values into grid options.
- */
-function _webform_grid_options($text) {
-  $options = array();
-  $rows = array_filter(explode("\n", _webform_filter_values(trim($text), NULL, NULL, NULL, FALSE)));
-
-  foreach ($rows as $option) {
-    $option = trim($option);
-    if (preg_match('/^([^|]+)\|(.*)$/', $option, $matches)) {
-      $options[$matches[1]] = $matches[2];
-    }
-    else {
-      $options[$option] = $option;
-    }
-  }
-  return $options;
-}
Index: webform.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.install,v
retrieving revision 1.40.2.2
diff -u -r1.40.2.2 webform.install
--- webform.install	8 Mar 2010 01:04:08 -0000	1.40.2.2
+++ webform.install	14 Mar 2010 04:00:09 -0000
@@ -310,11 +310,10 @@
       ),
       'no' => array(
         'description' => 'Usually this value is 0, but if a field has multiple values (such as a time or date), it may require multiple rows in the database.',
-        'type' => 'int',
-        'size' => 'tiny',
-        'unsigned' => TRUE,
+        'type' => 'varchar',
+        'length' => 128,
         'not null' => TRUE,
-        'default' => 0,
+        'default' => '0',
       ),
       'data' => array(
         'description' => 'The submitted value of this field, may be serialized for some components.',
@@ -897,6 +896,203 @@
 }
 
 /**
+ * Convert the "no" column to be a varchar column instead of an integer.
+ */
+function webform_update_6311() {
+  $ret = array();
+
+  // Change the column.
+  db_drop_primary_key($ret, 'webform_submitted_data');
+  db_change_field($ret, 'webform_submitted_data', 'no', 'no', array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => '0'), array());
+  db_add_primary_key($ret, 'webform_submitted_data', array('nid', 'sid', 'cid', 'no'));
+
+  // Update date components.
+  $ret[] = update_sql("UPDATE {webform_submitted_data} SET no = 'month' WHERE no = '0' AND (nid, cid) IN (SELECT nid, cid FROM {webform_component} WHERE type = 'date')");
+  $ret[] = update_sql("UPDATE {webform_submitted_data} SET no = 'day' WHERE no = '1' AND (nid, cid) IN (SELECT nid, cid FROM {webform_component} WHERE type = 'date')");
+  $ret[] = update_sql("UPDATE {webform_submitted_data} SET no = 'year' WHERE no = '2' AND (nid, cid) IN (SELECT nid, cid FROM {webform_component} WHERE type = 'date')");
+
+  // Update time components.
+  $ret[] = update_sql("UPDATE {webform_submitted_data} SET no = 'hour' WHERE no = '0' AND (nid, cid) IN (SELECT nid, cid FROM {webform_component} WHERE type = 'time')");
+  $ret[] = update_sql("UPDATE {webform_submitted_data} SET no = 'minute' WHERE no = '1' AND (nid, cid) IN (SELECT nid, cid FROM {webform_component} WHERE type = 'time')");
+  $ret[] = update_sql("UPDATE {webform_submitted_data} SET no = 'ampm' WHERE no = '2' AND (nid, cid) IN (SELECT nid, cid FROM {webform_component} WHERE type = 'time')");
+
+  // Updating of select and grid components is done in following updates.
+
+  return $ret;
+}
+
+/**
+ * Convert select options to use numeric keys if none are manually specified.
+ */
+function webform_update_6312() {
+  $ret = array();
+
+  $result = db_query("SELECT * FROM {webform_component} WHERE type = 'select'");
+  while ($row = db_fetch_object($result)) {
+    $extra = unserialize($row->extra);
+    $lines = explode("\n", $extra['items']);
+
+    // Get a list of items that have manual keys or no keys at all.
+    $keys = array();
+    $values = array();
+    foreach ($lines as $line) {
+      $line = rtrim($line, "\r\n");
+      if (strlen($line) == 0) {
+        continue;
+      }
+      $matches = array();
+      if (preg_match('/^\<([^>]*)\>$/', $line, $matches)) {
+        $keys[] = '<group>';
+        $values = $line;
+      }
+      elseif (preg_match('/^([^|]+)\|(.*)$/', $line, $matches)) {
+        $keys[] = $matches[1];
+        $values[] = $matches[2];
+      }
+      else {
+        $keys[] = '<unknown>';
+        $values[] = $line;
+      }
+    }
+
+    // Assign new keys to items that have none.
+    $new_key = 0;
+    $new_keys = array();
+    $items = '';
+    foreach ($keys as $n => $key) {
+      if ($key == '<group>') {
+        $items .= $values[$n] . "\n";
+      }
+      elseif ($key == '<unknown>') {
+        while (in_array($new_key, $keys, TRUE) || in_array($new_key, $new_keys, TRUE)) {
+          $new_key++;
+        }
+        $new_keys[$n] = $new_key;
+        $items .= $new_key . '|' . $values[$n] . "\n";
+      }
+      else {
+        $items .= $key . '|' . $values[$n] . "\n";
+      }
+    }
+
+    // While we're here, get rid of the 'Y' value for options.
+    foreach ($extra as $key => $value) {
+      if ($value === 'Y') {
+        $extra[$key] = '1';
+      }
+      elseif ($value === 'N') {
+        $extra[$key] = 0;
+      }
+    }
+
+    // Update the component.
+    $extra['items'] = $items;
+    db_query("UPDATE {webform_component} SET extra = '%s' WHERE nid = %d AND cid = %d", serialize($extra), $row->nid, $row->cid);
+
+    // Update the saved results.
+    foreach ($new_keys as $delta => $new_key) {
+      db_query("UPDATE {webform_submitted_data} SET data = '%s' WHERE nid = %d AND cid = %d AND data = '%s'", $new_key, $row->nid, $row->cid, $values[$delta]);
+    }
+
+    // Delete empty rows, which are no longer stored for select lists.
+    db_query("DELETE FROM {webform_submitted_data} WHERE data = '' AND nid = %d AND cid = %d");
+  }
+
+  return $ret;
+}
+
+/**
+ * Create keys for all questions (which don't currently have keys at all),
+ * create keys for all options that don't yet have any, and then convert the
+ * existing data to use these keys.
+ */
+function webform_update_6313() {
+  $ret = array();
+
+  $result = db_query("SELECT * FROM {webform_component} WHERE type = 'grid'");
+  while ($row = db_fetch_object($result)) {
+    $extra = unserialize($row->extra);
+    $lines = explode("\n", $extra['options']);
+
+    // Get a list of items that have manual keys or no keys at all.
+    $keys = array();
+    $values = array();
+    foreach ($lines as $line) {
+      $line = rtrim($line, "\r\n");
+      if (strlen($line) == 0) {
+        continue;
+      }
+      $matches = array();
+      if (preg_match('/^([^|]+)\|(.*)$/', $line, $matches)) {
+        $keys[] = $matches[1];
+        $values[] = $matches[2];
+      }
+      else {
+        $keys[] = '<unknown>';
+        $values[] = $line;
+      }
+    }
+
+    // Assign new keys to options that have none.
+    $new_key = 0;
+    $new_keys = array();
+    $options = '';
+    foreach ($keys as $n => $key) {
+      if ($key == '<unknown>') {
+        while (in_array($new_key, $keys, TRUE) || in_array($new_key, $new_keys, TRUE)) {
+          $new_key++;
+        }
+        $new_keys[$n] = $new_key;
+        $options .= $new_key . '|' . $values[$n] . "\n";
+      }
+      else {
+        $options .= $key . '|' . $values[$n] . "\n";
+      }
+    }
+    $extra['options'] = $options;
+
+    // Assign question keys. This is easier since they don't have keys at all.
+    $lines = explode("\n", $extra['questions']);
+    $questions = array();
+    foreach ($lines as $delta => $line) {
+      $line = rtrim($line, "\r\n");
+      if (strlen($line) == 0) {
+        continue;
+      }
+      $questions[$delta] = $delta . '|' . $line;
+    }
+    $extra['questions'] = implode("\n", $questions);
+
+    // While we're here, get rid of the 'Y' value for options.
+    foreach ($extra as $key => $value) {
+      if ($value === 'Y') {
+        $extra[$key] = '1';
+      }
+      elseif ($value === 'N') {
+        $extra[$key] = 0;
+      }
+    }
+
+    // Update the component.
+    db_query("UPDATE {webform_component} SET extra = '%s' WHERE nid = %d AND cid = %d", serialize($extra), $row->nid, $row->cid);
+
+    // Convert the option values into keys if new ones were created.
+    foreach ($new_keys as $delta => $new_key) {
+      db_query("UPDATE {webform_submitted_data} SET data = '%s' WHERE nid = %d AND cid = %d AND data = '%s'", $new_key, $row->nid, $row->cid, $values[$delta]);
+    }
+
+    // Note: Converting the question values into keys is not necessary because
+    // data was already stored based on the question position. Since we assigned
+    // permanent keys based on position, all our keys are already accurate.
+
+    // Delete empty rows, which are no longer stored for grids.
+    db_query("DELETE FROM {webform_submitted_data} WHERE data = '' AND nid = %d AND cid = %d");
+  }
+
+  return $ret;
+}
+
+/**
  * Recursively delete all files and folders in the specified filepath, then
  * delete the containing folder.
  *
Index: includes/webform.submissions.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.submissions.inc,v
retrieving revision 1.18.2.3
diff -u -r1.18.2.3 webform.submissions.inc
--- includes/webform.submissions.inc	10 Mar 2010 03:53:10 -0000	1.18.2.3
+++ includes/webform.submissions.inc	14 Mar 2010 04:00:11 -0000
@@ -22,11 +22,7 @@
     }
 
     if (is_array($values)) {
-      $delta = 0;
-      foreach ($values as $key => $value) {
-        $data[$cid]['value'][$delta] = $value;
-        $delta++;
-      }
+      $data[$cid]['value'] = $values;
     }
     else {
       $data[$cid]['value'][0] = $values;
@@ -81,7 +77,7 @@
 
   foreach ($submission->data as $cid => $values) {
     foreach ($values['value'] as $delta => $value) {
-      db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) VALUES (%d, %d, %d, %d, '%s')", $node->nid, $submission->sid, $cid, $delta, $value);
+      db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) VALUES (%d, %d, %d, '%s', '%s')", $node->nid, $submission->sid, $cid, $delta, $value);
     }
   }
 
