diff --git a/ChangeLog b/ChangeLog
index 3835aad031..6e7dd94de3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -26,6 +26,7 @@ phpMyAdmin - ChangeLog
+ rfe #908 Improvements for the table editor (index creation)
+ rfe #1426 Navigation state lost on reload
- bug #4439 Table list in left panel doesn't expand
++ rfe Improved validation when inserting data
4.2.8.0 (not yet released)
diff --git a/js/big_ints.js b/js/big_ints.js
new file mode 100644
index 0000000000..27576bca5f
--- /dev/null
+++ b/js/big_ints.js
@@ -0,0 +1,67 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * phpMyAdmin's BigInts library
+ */
+
+/**
+ * @var BigInts object to handle big integers (in string)
+ * as JS can handle upto 53 bits of precision only.
+ */
+var BigInts = {
+
+ /**
+ * Compares two integer strings
+ *
+ * @param int1 the string representation of 1st integer
+ * @param int2 the string representation of 2nd integer
+ *
+ * @return int 0 if equal, < 0 if int1 < int2, else > 0
+ */
+ compare: function(int1, int2) {
+ // trim integers
+ int1 = int1.trim();
+ int2 = int2.trim();
+ // length of integer strings
+ var len1 = int1.length;
+ var len2 = int2.length;
+ // integer is -ve or not
+ var isNeg1 = int1[0] === '-' ? true : false;
+ var isNeg2 = int2[0] === '-' ? true : false;
+ // Sign of int1 != int2 then no actual comparison
+ // is needed we can return result directly
+ if (isNeg1 !== isNeg2) {
+ return (isNeg1 === true ? -1 : 1);
+ }
+ // replace - sign with 0
+ int1[0] = isNeg1 ? '0' : int1[0];
+ int2[0] = isNeg2 ? '0' : int2[0];
+ // pad integers with 0 to make them
+ // equal length
+ int1 = BigInts.lpad(int1, len2);
+ int2 = BigInts.lpad(int2, len1);
+ // Now they are good to compare as strings
+ if (int1 !== int2) {
+ return (int1 < int2 ? -1 : 1);
+ }
+ return 0;
+ },
+
+ /**
+ * Adds leading zeros to a integer given a total length
+ *
+ * @param int the string representation of the integer
+ * @param total the total length required
+ *
+ * @return int the integer of length given with added leading
+ * zeros if necessary
+ */
+ lpad: function(int, total){
+ var len = int.length;
+ var pad = '';
+ while(len < total) {
+ pad += '0';
+ len++;
+ }
+ return (pad + int);
+ }
+};
diff --git a/js/tbl_change.js b/js/tbl_change.js
index c8d684e901..3c70eba503 100644
--- a/js/tbl_change.js
+++ b/js/tbl_change.js
@@ -151,19 +151,37 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
{
var evt = window.event || arguments.callee.caller.arguments[0];
var target = evt.target || evt.srcElement;
+ var $this_input = $("input[name='fields[multi_edit][" + multi_edit + "][" +
+ urlField + "]']");
+ // check if it is textarea rather than input
+ if ($this_input.length === 0) {
+ $this_input = $("textarea[name='fields[multi_edit][" + multi_edit + "][" +
+ urlField + "]']");
+ }
//To generate the textbox that can take the salt
var new_salt_box = "
";
//If AES_ENCRYPT is Selected then append the new textbox for salt
- if (target.value == "AES_DECRYPT" || target.value == "AES_ENCRYPT") {
+ if (target.value === 'AES_DECRYPT' || target.value === 'AES_ENCRYPT') {
if (!($("#salt_" + target.id).length)) {
- $("#" + target.id).parent().next("td").next("td").find("input[name*='fields']").after(new_salt_box);
+ $this_input.after(new_salt_box);
}
-
+ if ($this_input.data('type') !== 'HEX') {
+ $('#' + target.id).addClass('invalid_value');
+ return false;
+ }
+ } else if(target.value === 'MD5' &&
+ typeof $this_input.data('maxlength') !== 'undefined' &&
+ $this_input.data('maxlength') < 32
+ ){
+ $('#' + target.id).addClass('invalid_value');
+ return false;
} else {
+ $('#' + target.id).removeClass('invalid_value');
//The value of the select is no longer AES_ENCRYPT, remove the textbox for salt
+ $('#salt_' + target.id).prev('br').remove();
$("#salt_" + target.id).remove();
}
@@ -172,11 +190,6 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
// Unchecks the Ignore checkbox for the current row
$("input[name='insert_ignore_" + multi_edit + "']").prop('checked', false);
- var $this_input = $("input[name='fields[multi_edit][" + multi_edit + "][" + urlField + "]']");
- // check if it is textarea rather than input
- if ($this_input.length === 0) {
- $this_input = $("textarea[name='fields[multi_edit][" + multi_edit + "][" + urlField + "]']");
- }
// Does this field come from datepicker?
if ($this_input.data('comes_from') == 'datepicker') {
@@ -224,16 +237,29 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
}
}
}
- //validate for integer type
- if (theType.substring(0, 3) == "int") {
+ //validation for integer type
+ if ($this_input.data('type') === 'INT') {
+ var min = $this_input.attr('min');
+ var max = $this_input.attr('max');
+ var value = $this_input.val();
$this_input.removeClass("invalid_value");
- if (isNaN($this_input.val())) {
+ if (isNaN(value) || BigInts.compare(value, min) < 0 ||
+ BigInts.compare(value, max) > 0
+ ) {
$this_input.addClass("invalid_value");
return false;
}
- }
- // validate binary & blob types
- if (theType.indexOf('blob') > -1 || theType.indexOf('binary') > -1) {
+ //validation for CHAR types
+ } else if ($this_input.data('type') === 'CHAR') {
+ var len = $this_input.val().length;
+ var maxlen = $this_input.data('maxlength');
+ $this_input.removeClass("invalid_value");
+ if (typeof maxlen !== 'undefined' && len > maxlen) {
+ $this_input.addClass("invalid_value");
+ return false;
+ }
+ // validate binary & blob types
+ } else if ($this_input.data('type') === 'HEX') {
$this_input.removeClass("invalid_value");
if ($this_input.val().match(/^[a-f0-9]*$/i) === null) {
$this_input.addClass("invalid_value");
diff --git a/libraries/insert_edit.lib.php b/libraries/insert_edit.lib.php
index 6d8fe2d91a..98021d59a5 100644
--- a/libraries/insert_edit.lib.php
+++ b/libraries/insert_edit.lib.php
@@ -586,7 +586,7 @@ function PMA_getNullifyCodeForNullColumn($column, $foreigners, $foreignData)
* @param integer $tabindex_for_value offset for the values tabindex
* @param integer $idindex id index
* @param array $data description of the column field
- * @param array $special_chars special characters
+ * @param string $special_chars special characters
* @param array $foreignData data about the foreign keys
* @param boolean $odd_row whether row is odd
* @param array $paramTableDbArray array containing $table and $db
@@ -618,6 +618,8 @@ function PMA_getValueColumn($column, $backup_field, $column_name_appendix,
$is_upload, $biggest_max_file_size,
$default_char_editing, $no_support_types, $gis_data_types, $extracted_columnspec
) {
+ // HTML5 data-* attribute data-type
+ $data_type = $GLOBALS['PMA_Types']->getTypeClass($column['True_Type']);
$html_output = '';
if ($foreignData['foreign_link'] == true) {
@@ -644,7 +646,7 @@ function PMA_getValueColumn($column, $backup_field, $column_name_appendix,
$html_output .= PMA_getTextarea(
$column, $backup_field, $column_name_appendix, $unnullify_trigger,
$tabindex, $tabindex_for_value, $idindex, $text_dir,
- $special_chars_encoded
+ $special_chars_encoded, $data_type
);
} elseif (strstr($column['pma_type'], 'text')) {
@@ -652,7 +654,7 @@ function PMA_getValueColumn($column, $backup_field, $column_name_appendix,
$html_output .= PMA_getTextarea(
$column, $backup_field, $column_name_appendix, $unnullify_trigger,
$tabindex, $tabindex_for_value, $idindex, $text_dir,
- $special_chars_encoded
+ $special_chars_encoded, $data_type
);
$html_output .= "\n";
if (strlen($special_chars) > 32000) {
@@ -802,12 +804,13 @@ function PMA_dispRowForeignData($backup_field, $column_name_appendix,
* @param string $text_dir text direction
* @param string $special_chars_encoded replaced char if the string starts
* with a \r\n pair (0x0d0a) add an extra \n
+ * @param string $data_type the html5 data-* attribute type
*
* @return string an html snippet
*/
function PMA_getTextarea($column, $backup_field, $column_name_appendix,
- $unnullify_trigger,
- $tabindex, $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded
+ $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex,
+ $text_dir, $special_chars_encoded, $data_type
) {
$the_class = '';
$textAreaRows = $GLOBALS['cfg']['TextareaRows'];
@@ -832,13 +835,14 @@ function PMA_getTextarea($column, $backup_field, $column_name_appendix,
$html_output = $backup_field . "\n"
. '';
@@ -1076,7 +1080,7 @@ function PMA_getColumnSetValueAndSelectSize($column, $extracted_columnspec)
*
* @param array $column description of column in given table
* @param array $data data to edit
- * @param array $special_chars special characters
+ * @param string $special_chars special characters
* @param integer $biggest_max_file_size biggest max file size for uploading
* @param string $backup_field hidden input field
* @param string $column_name_appendix the name atttibute
@@ -1125,14 +1129,14 @@ function PMA_getBinaryAndBlobColumn(
$html_output .= "\n" . PMA_getTextarea(
$column, $backup_field, $column_name_appendix, $unnullify_trigger,
$tabindex, $tabindex_for_value, $idindex, $text_dir,
- $special_chars_encoded
+ $special_chars_encoded, 'HEX'
);
} else {
// field size should be at least 4 and max $GLOBALS['cfg']['LimitChars']
$fieldsize = min(max($column['len'], 4), $GLOBALS['cfg']['LimitChars']);
$html_output .= "\n" . $backup_field . "\n" . PMA_getHTMLinput(
$column, $column_name_appendix, $special_chars, $fieldsize,
- $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex
+ $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, 'HEX'
);
}
$html_output .= sprintf($fields_type_html, $fields_type_val);
@@ -1161,17 +1165,19 @@ function PMA_getBinaryAndBlobColumn(
*
* @param array $column description of column in given table
* @param string $column_name_appendix the name attribute
- * @param array $special_chars special characters
+ * @param string $special_chars special characters
* @param integer $fieldsize html field size
* @param string $unnullify_trigger validation string
* @param integer $tabindex tab index
* @param integer $tabindex_for_value offset for the values tabindex
* @param integer $idindex id index
+ * @param string $data_type the html5 data-* attribute type
*
* @return string an html snippet
*/
-function PMA_getHTMLinput($column, $column_name_appendix, $special_chars,
- $fieldsize, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex
+function PMA_getHTMLinput(
+ $column, $column_name_appendix, $special_chars, $fieldsize, $unnullify_trigger,
+ $tabindex, $tabindex_for_value, $idindex, $data_type
) {
$input_type = 'text';
// do not use the 'date' or 'time' types here; they have no effect on some
@@ -1189,27 +1195,24 @@ function PMA_getHTMLinput($column, $column_name_appendix, $special_chars,
$the_class .= ' datetimefield';
}
$input_min_max = false;
- if (!$GLOBALS['cfg']['ShowFunctionFields']) {
- if (in_array(
- $column['True_Type'],
- $GLOBALS['PMA_Types']->getIntegerTypes()
- )) {
- $input_type = 'number';
- $is_unsigned = substr($column['pma_type'], -9) === ' unsigned';
- $min_max_values = $GLOBALS['PMA_Types']->getIntegerRange(
- $column['True_Type'], ! $is_unsigned
- );
- $input_min_max = 'min="' . $min_max_values[0] . '" '
- . 'max="' . $min_max_values[1] . '" ';
- }
+ if (in_array($column['True_Type'], $GLOBALS['PMA_Types']->getIntegerTypes())) {
+ $extracted_columnspec = PMA_Util::extractColumnSpec($column['Type']);
+ $is_unsigned = $extracted_columnspec['unsigned'];
+ $min_max_values = $GLOBALS['PMA_Types']->getIntegerRange(
+ $column['True_Type'], ! $is_unsigned
+ );
+ $input_min_max = 'min="' . $min_max_values[0] . '" '
+ . 'max="' . $min_max_values[1] . '"';
+ $data_type = 'INT';
}
return 'getTypeClass($column['True_Type']);
$fieldsize = PMA_getColumnSize($column, $extracted_columnspec);
$html_output = $backup_field . "\n";
if ($column['is_char']
@@ -1327,12 +1332,12 @@ function PMA_getValueColumnForOtherDatatypes($column, $default_char_editing,
$html_output .= PMA_getTextarea(
$column, $backup_field, $column_name_appendix, $unnullify_trigger,
$tabindex, $tabindex_for_value, $idindex, $text_dir,
- $special_chars_encoded
+ $special_chars_encoded, $data_type
);
} else {
$html_output .= PMA_getHTMLinput(
- $column, $column_name_appendix, $special_chars,
- $fieldsize, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex
+ $column, $column_name_appendix, $special_chars, $fieldsize,
+ $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data_type
);
if ($column['Extra'] == 'auto_increment') {
diff --git a/tbl_change.php b/tbl_change.php
index 135ee2568c..2bdbe52cd3 100644
--- a/tbl_change.php
+++ b/tbl_change.php
@@ -75,6 +75,7 @@ $scripts = $header->getScripts();
$scripts->addFile('functions.js');
$scripts->addFile('sql.js');
$scripts->addFile('tbl_change.js');
+$scripts->addFile('big_ints.js');
$scripts->addFile('jquery/jquery-ui-timepicker-addon.js');
$scripts->addFile('gis_data_editor.js');
diff --git a/tbl_replace.php b/tbl_replace.php
index c8cfb84a92..37bac523ef 100644
--- a/tbl_replace.php
+++ b/tbl_replace.php
@@ -446,6 +446,7 @@ if (! empty($return_to_sql_query)) {
}
$scripts->addFile('tbl_change.js');
+$scripts->addFile('big_ints.js');
$active_page = $goto_include;
diff --git a/test/libraries/PMA_insert_edit_test.php b/test/libraries/PMA_insert_edit_test.php
index 695783aea4..69a9054690 100644
--- a/test/libraries/PMA_insert_edit_test.php
+++ b/test/libraries/PMA_insert_edit_test.php
@@ -848,15 +848,16 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$column = array();
$column['is_char'] = true;
$column['Type'] = 'char(10)';
+ $column['True_Type'] = 'char';
$result = PMA_getTextarea(
- $column, 'a', 'b', 'd', 2, 0, 1, "abc/", 'foobar'
+ $column, 'a', 'b', 'd', 2, 0, 1, "abc/", 'foobar', 'CHAR'
);
$this->assertTag(
PMA_getTagArray(
'',
$result
);
@@ -1288,8 +1289,8 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$this->assertEquals(
"\na\n"
- . ''
+ . ''
. '',
$result
);
@@ -1306,31 +1307,31 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$column = array();
$column['pma_type'] = 'date';
$column['True_Type'] = 'date';
- $result = PMA_getHTMLinput($column, 'a', 'b', 30, 'c', 23, 2, 0);
+ $result = PMA_getHTMLinput($column, 'a', 'b', 30, 'c', 23, 2, 0, 'DATE');
$this->assertEquals(
- '',
+ '',
$result
);
// case 2 datetime
$column['pma_type'] = 'datetime';
$column['True_Type'] = 'datetime';
- $result = PMA_getHTMLinput($column, 'a', 'b', 30, 'c', 23, 2, 0);
+ $result = PMA_getHTMLinput($column, 'a', 'b', 30, 'c', 23, 2, 0, 'DATE');
$this->assertEquals(
- '',
+ '',
$result
);
// case 3 timestamp
$column['pma_type'] = 'timestamp';
$column['True_Type'] = 'timestamp';
- $result = PMA_getHTMLinput($column, 'a', 'b', 30, 'c', 23, 2, 0);
+ $result = PMA_getHTMLinput($column, 'a', 'b', 30, 'c', 23, 2, 0, 'DATE');
$this->assertEquals(
- '',
+ '',
$result
);
}
@@ -1374,6 +1375,7 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$column['len'] = 20;
$column['is_char'] = true;
$column['Type'] = 'char(25)';
+ $column['True_Type'] = 'char';
$GLOBALS['cfg']['CharEditing'] = '';
$GLOBALS['cfg']['MaxSizeForInputField'] = 30;
$GLOBALS['cfg']['MinSizeForInputField'] = 10;
@@ -1394,8 +1396,9 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$this->assertEquals(
"a\n\na\n"
. '',
+ . 'data-maxlength="25" rows="5" cols="1" dir="/" '
+ . 'id="field_1_3" c tabindex="34" data-type="CHAR">'
+ . '<',
$result
);
@@ -1411,10 +1414,10 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$this->assertEquals(
"a\n"
- . '',
+ . ''
+ . '',
$result
);
diff --git a/themes/original/css/common.css.php b/themes/original/css/common.css.php
index 4f0a86aa06..c2d48c2c7c 100644
--- a/themes/original/css/common.css.php
+++ b/themes/original/css/common.css.php
@@ -1530,6 +1530,7 @@ input[type=text].invalid_value,
input[type=password].invalid_value,
input[type=number].invalid_value,
input[type=date].invalid_value,
+select.invalid_value,
.invalid_value {
background: #FFCCCC;
}
diff --git a/themes/pmahomme/css/common.css.php b/themes/pmahomme/css/common.css.php
index b0197c30c1..4fc432cce4 100644
--- a/themes/pmahomme/css/common.css.php
+++ b/themes/pmahomme/css/common.css.php
@@ -1993,6 +1993,7 @@ input[type=text].invalid_value,
input[type=password].invalid_value,
input[type=number].invalid_value,
input[type=date].invalid_value,
+select.invalid_value,
.invalid_value {
background: #FFCCCC;
}