I have a portion of a MySQL query which is designed to save a password using SHA512-CRYPT:
SELECT ENCRYPT('firstpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16)))
I need to port the application to use PostgreSQL, and as such, the statement is not compatible.
My attempt in PostgreSQL is like so:
SELECT CRYPT('firstpassword'::text, CONCAT('$6$', SUBSTRING(ENCODE(DIGEST(RANDOM()::text , 'sha1'), 'hex') FROM '.{16}$')))
When tested in component parts, each of these implementations appear identical, but as completed statements, the output differs.
I have found that the CONCAT statements (that generate the salt) appear to provide identical output.
If I try comparing the output of CRYPT or ENCRYPT using simple plaintext words, the output is identical. However, if I combine it with the output of a salt, the output differs;
MySQL:
SELECT ENCRYPT( 'firstpassword', '$6$ae73a5ca7d3e5b11' )
Produces: $6$ae73a5ca7d3e5b11$v/RbcEEx4VR37VMUF6gBnPNo2ptSyU...
PostgreSQL:
SELECT CRYPT('firstpassword'::text, '$6$ae73a5ca7d3e5b11'::text)
Produces: $6eTK2KpfoaQM
Can someone explain why these statements are diverging or suggest a better way to implement this MySQL query?
They diverge because they use different encryption algorithms.
The first thing you want to do is to get very familiar with the pg_crypto documentation. See http://www.postgresql.org/docs/9.2/static/pgcrypto.html
My suspicion is that you probably want to switch from something like encrypt/crypt to the use of SHA-2 for the actual password hashing so you can specifically control the algorithms and ensure compatibility on both sides.
SHA512-CRYPT is not supported by PostgreSQL core or the pgcrypto extension shipped with the main sources. The crypt function shown in the question comes from pgcrypto and does only support bf, md5, des and xdes (see "supported algorithm" in the documentation).
But you may use the shacrypt extension:
test=# create extension shacrypt ; -- (after installing from the sources)
CREATE EXTENSION
test=# select sha512_crypt('firstpassword', '$6$ae73a5ca7d3e5b11' );
sha512_crypt
------------------------------------------------------------------------------------------------------------
$6$ae73a5ca7d3e5b11$v/RbcEEx4VR37VMUF6gBnPNo2ptSyU3ys1sg6i8hhBrcfBeLY6hpsfvXR67bwwjMainpPEaLkYV6eO0ow0xVH.
which gives the same result as MySQL's SELECT ENCRYPT( 'firstpassword', '$6$ae73a5ca7d3e5b11' )
Related
Yes, of course, I know, there are many different generators created on Javascipt, php, etc. and even applications and web-services that allow generating sql.
But I’d like to have sql functions library which can be used during generating data right away from MySQL script and stored procedures.
Now I'm creating my own helper functions (and it’s quite tedious) that work roughly like bellow:
(fl_* - are functions that return fake data of corresponding type and features.)
-- create a fake user:
call sp_user_add(fl_login(), fl_email(), fl_gender(), #user_id);
-- add a fake post:
call sp_post_add(#user_id, fl_title(true, 1, 10), fl_body(true, 3, 20), #post_id);
You need to know mysql random data generator stored procedure.
See http://www.generatedata.com/. Here you can select the SQL-Tab and select the number of rows you want to get created. The result is a SQL-script you can copy-paste. I found this very handy...
I have a complicated query and since I need that my module work on both mysql and postgres, I need to write two version of it.
Unfortunately, I don't know how I can check if the db I use is mysql or postgres, to know which query use. Do you know if a function can return this value?
As #kordirko says, one option is to query the server version: SELECT version(); will work on both MySQL and PostgreSQL, though not most other database engines.
Parsing version strings is always a bit fragile though, and MySQL returns just a version number like 5.5.32 wheras PostgreSQL returns something like PostgreSQL 9.4devel on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8), 64-bit. What do you do if you're connecting to a PostgreSQL-compatible database like EnterpriseDB Postgres Plus, or a MySQL-compatible database?
It's much safer to use the Drupal function for the purpose, DatabaseConnection::databaseType. This avoids a query round-trip to the DB, will work on databases that won't understand/accept SELECT version(), and will avoid the need to parse version strings.
You'll find this bug report useful; it suggests that the correct usage is Database::getConnection()->databaseType().
(I've never even used Drupal, I just searched for this).
As long as the abstract DatabaseConnection class extends PDO class, you can invoking pdo methods in order to know the current database driver.
For instance:
$conn = Database::getConnection();
print $conn->getAttribute($conn::ATTR_DRIVER_NAME); #returns mysql, pgsql...
There is a second way to do it using DatabaseConnection::driver():
print $conn->driver();
or DatabaseConnection::databaseType();
print $conn->databaseType();
Note that DatabaseConnection::driver() and DatabaseConnection::databaseType() are similar functions but not equals!
The return value from DatabaseConnection::driver() method depends on the implementation and other factors.
in the Drupal Database API page:
database.inc abstract public DatabaseConnection::driver()
This is not necessarily the same as the type of the database itself. For instance, there could be two MySQL drivers, mysql and mysql_mock. This function would return different values for each, but both would return "mysql" for databaseType().
In the most cases you just gonna want to use only
$conn->getAttribute($conn::ATTR_DRIVER_NAME)
or $conn->databaseType()
If you want get more specific properties, you should take advantage the PHP ReflectionClass features:
$conn = Database::getConnection();
$ref = new ReflectionClass($conn);
#ref->getProperties, ref->getConstants $ref->isAbstract...
Reference:
PDO::getAttribute
PDO::ATTR_DRIVER_NAME
Drupal Database API
Drupal Base Database API class
I've searched and can't seem to find quite what I'm looking for.
I'm running a PL/SQL script in Oracle, and attempting to insert records into a table in MySQL via database link using MySQL ODBC 5.2 Unicode Driver.
The link works fine, I can do complex queries in Oracle using it, and do various inserts and updates on records there.
Where it fails is in trying to insert a record into a MySQL table that has a column of type bit(1).
It is basically a cursor for loop, with the insert statement looking something like:
INSERT INTO "app_user"#mobileapi (USERNAME, VERSION, ACCOUNT_EXPIRED, ACCOUNT_LOCKED, PASSWD, PASSWORD_EXPIRED)
VALUES (CU_rec.USERNAME, CU_rec.VERSION, CU_rec.ACCOUNT_EXPIRED, CU_rec.ACCOUNT_LOCKED, CU_rec.PASSWD, CU_rec.PASSWORD_EXPIRED)
Some of the target columns, like ACCOUNT_EXPIRED, ACCOUNT_LOCKED, etc. are the bit(1) columns in MySQL. Given that I can convert the data types in the cursor CU_rec to pretty much anything I want in Oracle, how can I get them inserted into the target? I've tried everything I can think of, and I just keep getting:
Error report:
ORA-28500: connection from ORACLE to a non-Oracle system returned this message:
[MySQL][ODBC 5.2(w) Driver][mysqld-5.6.10]Data too long for column 'ACCOUNT_EXPIRED' at row 1 {HY000,NativeErr = 1406}
ORA-02063: preceding 2 lines from MOBILEAPI
ORA-06512: at line 44
28500. 00000 - "connection from ORACLE to a non-Oracle system returned this message:"
*Cause: The cause is explained in the forwarded message.
*Action: See the non-Oracle system's documentation of the forwarded
message.
Any help at all would be greatly appreciated.
Your problem is Oracle's default datatype conversion over ODBC; according to their own documentation they convert SQL_BINARY to a raw. Although not directly related, Oracle's comparison of MySQL and Oracle within SQL Developer also alludes to the fact that the automatic conversion from a MySQL bit is to an Oracle raw.
Extremely confusingly, MySQL's documentation indicates that a bit is converted to a SQL_BIT or a SQL_CHAR, which implies that it may work in the other direction1.
According to Microsoft's ODBC docs you should, theoretically, be able to use the CONVERT() function to transform this into a character, which should, theoretically, be translatable by MySQL.
insert into some_table#some_db (bit_col)
values( {fn convert(some_col, SQL_CHAR)} );
Failing that there's another couple of options, but it does depend on what you're attempting to insert into the MySQL database from Oracle and what the datatype is in Oracle. For instance you could use the Oracle CAST() function to convert between datatypes. For instance, the following would convert an integer to a binary double.
select cast(1 as binary_double) from dual
Unfortunately, you can't cast an integer to a raw, only a character or a rowid, so in order to convert to a raw you'd have to do the following:
select cast(to_char(1) as raw(1)) from dual
I've no idea whether MySQL will accept this but with some testing you should be able to work it out.
1. For clarity, I've never tried it in either direction.
Hah! I found a solution. Dropping it here in case it helps someone else. It's not pretty, but it works.
I used the old EXECUTE IMMEDIATE trick.
Basically, I created a variable sql_stmt varchar2(4000) and wrote code like:
sql_stmt := 'insert into "app_user"#mobileapi (USERNAME, VERSION, ACCOUNT_EXPIRED, ACCOUNT_LOCKED, CIPHER_PASSPHRASE, ENABLED, PASSWD, PASSWORD_EXPIRED)
values ('''||CU_rec.USERNAME||'','||CU_rec.VERSION||', '||CU_rec.ACCOUNT_EXPIRED||', '||CU_rec.ACCOUNT_LOCKED||', '''||CU_rec.CIPHER_PASSPHRASE||''', '||
CU_rec.ENABLED||', '''||CU_rec.PASSWD||''', '||CU_rec.PASSWORD_EXPIRED||')';
EXECUTE IMMEDIATE sql_stmt;
Something like that anyway (the quotes might not line up, as I hacked this a bit from the actual code). Looking at the contents of sql_stmt, I get:
insert into "app_user"#mobileapi (USERNAME, VERSION, ACCOUNT_EXPIRED, ACCOUNT_LOCKED, CIPHER_PASSPHRASE, ENABLED, PASSWD,PASSWORD_EXPIRED)
values ('user#email.com', 0, 0, 0, 'asdfastrwaebawavgansdhnsgjsjsh', 1, 'awercbcakwjerhcawuerawieubkahbewvkruh', 0)
The EXECUTE IMMEDIATE completes, and checking the target table, the values are there.
Possibly a crappy solution, but better than nothing.
i have 2 dbs: one in mySql and one in MongoDB with the same data inside...
i do the follow in mySQL:
Select tweet.testo From tweet Where tweet.testo like ‘%pizza%’
and this is the result:
1627 rows in set (2.79 sec)
but if i exec in mongo:
Db.tweets.find({text: /pizza/ }).explain()
this is the result:
nscannedObjects" : 1606334,
"n" : 1169,
or if i exec:
Db.tweets.find({text: /pizza/i }).explain()
this is the result:
"nscannedObjects" : 1606334,
"n" : 1641,
Why the number of rows/document in mysql/mongo find is different?
Why the number of rows/document in mysql/mongo find is different??
There could be 1000000000000000 reasons including the temperature of the sun on that particular day.
MongoDB and MySQL are two completely separate techs as such if you expect to keep both in synch you will need some kind of replicator between the two. You have not made us aware as to whether this is the case.
Also we have no idea of your coding, server setup, network setup and everything else so really we cannot even begin to answer this.
A good answer would be to say that the reason you are seeing this is because the data between the two is different...
As for the difference between:
Db.tweets.find({text: /pizza/ }).explain()
and
Db.tweets.find({text: /pizza/i }).explain()
This is because MySQL, by default, queries in lower case I believe and MongoDB (I know) does not as such it is case sensitive (this i makes it case insensitive).
However about replicators, here is a good one: https://docs.continuent.com/wiki/display/TEDOC/Replicating+from+MySQL+to+MongoDB
the mysql command
Select tweet.testo From tweet Where tweet.testo like ‘%pizza%’
is equivalent to MongoDB's
Db.tweets.find({text: /pizza/i })
I realized they both contain the same data, but in some cases the text in mysql was cut-off, so it resulted in less rows being returned.
To begin with your SQL query like '%pizza%' may not pickup entries that begin with the string 'pizza' because of the wildcard on the front. Try the following SQL query to rule out any syntactical differences with the matching logic in SQL and the Regex used by MongoDB
Select tweet.testo From tweet Where lower(tweet.testo) like ‘%pizza%’ or lower(tweet.testo) like ‘pizza%’
Disclaimer: I don't have mySQL in front of me just now so can't verify the leading wildcard behaviour described above, however this is consistent with other RDBMS so it's worth checking
I have installed WampServer 2.0 with MySQL 5.1.33.
I can do Numeric and String functions like
SELECT ABS(-2)orSELECT LOWER('ASD')
but with Date and Time Functions such as
SELECT CURDATE()orSELECT NOW()
I get
Error : no such function: CURDATE
Am I doing something wrong, is there anything I need to install?
Any help about where to start investigating?
There is no error message from MySQL with the text "No such function." I just did a grep on the whole source tree of MySQL 5.1, and that string does not occur anywhere (except in one comment).
My thought is that you aren't using MySQL, you're using SQLite. Because I can reproduce that error when I run the SQLite command-line shell:
$ sqlite3
sqlite> select curdate();
Error: no such function: curdate
sqlite> select now();
Error: no such function: now
In SQLite, the function to get the current date is simply date():
sqlite> select date();
2010-01-02
Many functions are different in SQlite and in MySQL (or any other product - if you except core functions, most functions provide the same functionality but with a different syntax). There is an open-source "compatibility library" implementing a large number of MySQL functions in SQLite on the Kansas State University CIS website
My inclination is to run a mysql repair install. if that didn't work, then i'd try to wamp reinst.
If SQLite had the same features as SQL, it would be amazing. But fortunately for query types with date comparisons it is possible to use existing SQLite functions.
An example of how I was able to carry out my query was as follows:
Using an interface type class declaring my ObjectDAO: 'PartidoDAO'.
#Query("select * from partido where fpartido>=DATE() and epartido = 'Santiago Bernabeu' ORDER BY fpartido LIMIT 1")
Partido getMoreRecentPartido();
If you want more information about functions related to date data types consult the web I invite you to consult this resource.
SQLite Date Functions.