How to ipv6 in integer in mysql databases? - mysql

I have one table where I store ip address. For faster access I store ip int also. This is the table structure.
CREATE TABLE `ipv6_test` (
`ip_string` varchar(20) DEFAULT NULL,
`ip_int` double DEFAULT null
) ;
I have used following method to get integer version of ip address.
new BigInteger(1, com.google.common.net.InetAddresses.forString(ip).getAddress());
Everything was working fine for ipv4 addresses, but my code started failing while storing ipv6 addresses.
How to store BigInteger in mysql database?
I'm thinking to use VARBINARY. Can I create index on VARBINARY column?
How is the VARBINARY's performance compared to index on integer?

INET6_ATON converts to a varbinary(16) for IPv4 + IPv6 storage.
Yes you can use VARBINARY as indexes. Its effectively a VARCHAR without character encoding. Its probably a bit slower than integers but ints can't do the same job. You probably won't notice it so don't prematurely optimize. Its only 16 characters maximum so its not much.
If you want to keep an text version for easy retrieval create a generated column converting the varbinary back.

Related

Why/how am I able to exceed the configured length of a varchar in MySQL? [my mistake, I can't]

[Edit: my mistake, read the wrong column for the type, the one I'm inserting into is LONGTEXT, not varchar(190)]
I am working with an application that stores the majority of its information in a MySQL database (MySQL server 5.7). One particular value I'm looking at has a 255 character limit enforced by the GUI but, when I looked at that column in the table where it's stored, it's set to varchar(190). I confirmed that I can enter 255-character values in the GUI and that they are not truncated, as I expected.
How can a varchar(190) column store >190 characters? Are there any consequences to doing it this way?
I read 11.4.1 The CHAR and VARCHAR Types and it states that anything over the limit should be truncated.
The answer is that I can't. Misread the column types because that column is varchar(255) when the application builds the schema in PostgreSQL. It's longtext* in MySQL, which explains why I was able to get past the 190 characters. I tried inserting my 230 char test string into the varchar(190) column and it throws an error, as expected.
Need more coffee.
*not sure why longtext, when the application GUI limits input to 255 characters, but I'll need to ask the people who built it.

Aes_decrypt on varchar column?

I made a small form for a website which stored the formdata with Aes_encrypt. The database that was used accidentally set the column type to varchar, and the collation to utf-8. Now when I run aes_decrypt, I get null as a result. Is there any way to still decrypt the data? Or is it now completely useless?
Thanks!

MySQL email address encryption

How to encrypt email address in MySQL? The column type is Char(255). MySQL version 5.5.33.
The email address should be able to retrieve back to plain text, since it will be used in the application.
I want to store the email address in encrypted form in char(255) column in MySQL database.
The AES_ENCYPT() function do not allow char(255) data type. I can change the data type provided performance is not reduced. Which is the best way to encrypt and store email address in MySQL?
I believe you may have another issue here. AES_ENCRYPT definitely can take a CHAR(n) datatype as a parameter. Tested on 5.5.29.
Do you get a specific error message?

Storing IPv6 Addresses in MySQL

As has been requested in "ipv6-capable inet_aton and inet_ntoa functions needed", there is currently no MySQL function for storing IPv6 addresses. What would be the recommended data type/function for storing/inserting? (I don't intend to store them as a string). I also don't want to separate the IPv6 address into 2 INT's.
How about:
BINARY(16)
That should be effective enough.
Currently there is no function to convert textual IPv6 addresses from/to binary in the MySQL server, as noted in that bug report. You either need to do it in your application or possibly make a UDF (User-Defined Function) in the MySQL server to do that.
UPDATE:
MySQL 5.6.3 has support for IPv6 addresses, see the following: "INET6_ATON(expr)".
The data type is VARBINARY(16) instead of BINARY(16) as I suggested earlier. The only reason for this is that the MySQL functions work for both IPv6 and IPv4 addresses. BINARY(16) is fine for storing only IPv6 addresses and saves one byte. VARBINARY(16) should be used when handling both IPv6 and IPv4 addresses.
An implementation for older versions of MySQL and MariaDB, see the following: "EXTENDING MYSQL 5 WITH IPV6 FUNCTIONS".
No one has posted a full working answer (and lots of examples use the Windows ::1 which can be very misleading for live (or "production") environments) any where (at least that I can find) so here is:
The format to store with.
Example INSERT query using a reasonably complex IPv6 IP address.
Example SELECT query that you will be able to echo the IPv6 IP address back to the client.
Troubleshooting to ensure you haven't missed any legacy code.
I changed all the column names to ipv6 to reflect that they properly support IPv6 (and that allows you to keep the old column ip intact). It is possible to store the ip column in the ipv6 column and then just DROP the ip column once you're certain the conversion has worked; when I actually have time I'll add that to this post.
IPv6 Data Type
As has been mentioned VARBINARY 16 is the desirable way to go until AMD blesses us with 128 bit CPUs and the databases are updated to support 128 bit integers (did I say that correctly?). IPv6 is 128 bit, not 64 bit.
CREATE TABLE `example`
(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`ipv6` VARBINARY(16) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8mb4_unicode_520_ci'
ENGINE=InnoDB;
IPv6 INSERT Query
We obviously need to store an IPv6 IP address before we can SELECT it; here is the PHP / SQL code:
$ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
$query1 = "INSERT INTO example (ipv6) VALUES (INET6_ATON('$ipv6'));";
IPv6 SELECT Query
The PHP / SQL code:
$ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
$query2 = "SELECT INET6_NTOA(ipv6) AS ipv6 FROM example WHERE ipv6=INET6_ATON('$ipv6');";
This will return fe80::202:b3ff:fe1e:8329; no, not the full IPv6 (which is FE80:0000:0000:0000:0202:B3FF:FE1E:8329), it's a condensed / shorthand version. There is code to make it the formal full-length version but this is to save myself and others time because this Q/A is the one that keeps coming up.
Important: just because some IPv6 addresses look like they'd fit in to bigint does not imply two minutes later someone with a larger IPv6 address won't stop by and wreak havoc.
Hopefully this will save some folks from the insanity of opening another two dozen tabs. When I have time in the future I'll add the extra PHP code that extends the condensed IPv6 to the full formal format.
Troubleshooting
If for some reason storing and/or retrieving IPv6 addresses is not working for you then grab yourself a copy of Advanced Find and Replace (works faster in Wine than Linux's native grep); use this predominantly for finding, not replacing. Ensure that your code is consistent everywhere in your software.
All $ip variables must be converted to $ipv6 so you know you've got that bit covered.
Do not forget to remove the ending ) for the next four steps:
Search for all instances of PHP inet_pton( functions and remove them.
Search for all instances of PHP inet_ntop( functions and remove them.
Search for all instances of SQL INET_ATON( functions and remove them.
Search for all instances of SQL INET_NTOA( functions and remove them.
Search for all instances of $ipv6 and ensure that all IP-IN-TO-SQL instances use INET6_ATON('$ipv6') and that all instances where IP-FROM-SQL use INET6_NTOA(ipv6) AS ipv6.
Search for all instances of $row1['ip'] and replace them with $row1['ipv6'].
Ensure that all instances of $ipv6 = use the following code (with your database object reference changed): $ipv6 = (isset($_SERVER['REMOTE_ADDR']) && strlen($_SERVER['REMOTE_ADDR']) > 0) ? mysqli_real_escape_string($db,$_SERVER['REMOTE_ADDR']) : mysqli_real_escape_string($db,getenv('REMOTE_ADDR'));.
Ensure that your tests use freshly tested IP addresses instead of potentially botched versions if you are aware that there was something wrong before you started debugging.
Excellent example however I noted the following.
That only works if one's version of mysql has as function for INET6_ATON.
Otherwise the error message might be something like: That FUNCTION DOES NOT EXIST.

Primary Key - VARBINARY or BLOB or VARCHAR for UUID primary key

I am using UUID as the primary key in one of the tables.
What are the pros-cons of having this field as a varchar/varbinary/blob?
The difference between text-based and binary-based UUID is a significant number of bytes - 16 for binary representation vs. 30+ for text - so binary is the way to go. I would opt for VARBINARY over BLOB - if only 'cause VARBINARY is the newer type (and coming from a SQL Server background, I know VARBINARY there can be stored in-row).