tidb cannot fuzzy query with like '_' for double byte character? - sql

In my program, I want to lookup "测试" with
select * from test where name like '测_';
After my test, I found that MySQL can, but tidb can't?

This seems to be working fine for me. What character set is your table, column and connection? What TiDB version are you using?
mysql> CREATE TABLE t1 (id char(2) character set utf8mb4 primary key);
Query OK, 0 rows affected (0.18 sec)
mysql> INSERT INTO t1 VALUES('测试'),('测x');
Query OK, 2 rows affected (0.12 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t1 WHERE id LIKE '测_';
+--------+
| id |
+--------+
| 测x |
| 测试 |
+--------+
2 rows in set (0.11 sec)
mysql> SELECT tidb_version();
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tidb_version() |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Release Version: v5.4.0
Edition: Community
Git Commit Hash: 55f3b24c1c9f506bd652ef1d162283541e428872
Git Branch: heads/refs/tags/v5.4.0
UTC Build Time: 2022-01-25 08:39:26
GoVersion: go1.16.4
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.11 sec)

Related

How does InnoDB take and retain record locks on READ COMMITTED LEVEL

mysql-refman-5.7, 14.7.2.1 Transaction Isolation Levels, says:
Under READ COMMITTED,
"For UPDATE or DELETE statements, InnoDB holds locks only for rows that it updates or deletes. Record locks for nonmatching rows are released after MySQL has evaluated the WHERE condition."
"However, if the WHERE condition includes an indexed column, and InnoDB uses the index, only the indexed column is considered when taking and retaining record locks. "
So, does 1st description conflicts with 2nd?
Here is the example:
mysql> show create table t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
`c` int(11) DEFAULT NULL,
KEY `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> select * from t order by b,c;
+---+------+------+
| a | b | c |
+---+------+------+
| 2 | 2 | 4 |
| 1 | 3 | 3 |
| 3 | 3 | 4 |
| 4 | 5 | 6 |
+---+------+------+
# Session A:
mysql> set TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update t set c = 5 where b=3 and c =3;
Query OK, 1 row affected (0.00 sec)
Session B:
mysql> set TRANSACTION ISOLATION LEVEL READ COMMITTED;
mysql> update t set c = 2 where b=3 and c =4; # waiting for lock
So, Session A locks all the records with b=3, why not it just locks the record with b=3 and c=3?

Clarifications about some SQL Injection commands

I'm struggling with a CTF(Capture The Flag) Web Challange on hackthebox, not being an expert in penetration testing I'm asking your help to explain me (with some comments) some commands used to reach the solution, expecially about the syntax and logic of the commands themselves. (A reference to the commands can be found here (click me), so you have the whole situation very clear).
I ask you to be very detailed, even on things that may seem trivial.
Leaving aside the base64 encoding (that I understand) I need to understand these commands and their related parameters (syntax and logic of the commands):
1th: {"ID":"1"}
2nd: {"ID": "1' or 1-- -"}
3rd: {"ID": "-1' union select * from (select 1)table1 JOIN (SELECT 2)table2 on 1=1-- -"}
About the 3rd command, I saw the same command but with an alteration of the table names, like this:
{"ID": "-1' union select * from (select 1)UT1 JOIN (SELECT 2)UT2 on 1=1-- -"}
What is the difference? Is the name given to the tables in the query irrelevant?
If you need further clarification or I haven't made myself clear, just tell it and I'll try to help you. Thank you in advance.
The stage of hacking is: recon, scanning, gaining access, maintaining access, and clearing tracks. Basically it's just obtain information, then do something with that information It seems that this SQL injection learning module is used to teach how to obtain information about the current system.
The basic of SQL injection is inserting SQL code/command/syntax. It's usually done in the WHERE clause (because webapp often have search feature, which is basically retrieving user input and inserting it on the where clause.
For example, the simplest vulnerability would be like this (assuming MySQL and PHP):
SELECT * FROM mytable WHERE mycolumn='$_GET[myparam]'
Payload is what you put inside the parameter (ex: myparam) to do SQL injection.
With such query, you can inject payload 1' OR 1=1 to test for SQL injection vulnerability.
1st payload
1st payload is used to check if there is an injection point (parameter that can be injected) or not.
If you change the parameter and there is a change on the output, then it means there is an injection point.
Otherwise there is no injection point
2nd payload
2nd payload is used to check if the target app have SQL injection vulnerability or not (would the app sanitize user's input or not).
If the app shows all output, then it means the app have SQL injection vulnerability. Explanation: because the query sent to RDBMS would become something like this
Before injection:
SELECT col1, col2, ... colN FROM mytable WHERE col1='myparam'
After injection:
SELECT col1, col2, ... colN FROM mytable WHERE col1='1' or 1-- -'
Please note that in MySQL, -- (minus-minus-space) is used to mark inline comment. So the actual query would be: SELECT col1, col2, ... colN FROM mytable WHERE col1='1' or 1
3rd payload
3rd payload is used to check how many column the query would SELECT. To understand this you have to understand subquery, join, and union (do a quick search, it's a very basic concept). The name or the table alias is not important (UT1 or UT2), it's just identifier so that it's not identical with current table alias.
If the query succeed (no error, the app display output), then it means the app query SELECTs 2 columns
If the query failed, then it means it's not 2 column, you can change the payload to check for 3 columns, 4 columns, etc...
Example for checking if SELECT statement have 3 columns:
-1' union select * from (select 1)UT1 JOIN (SELECT 2)UT2 on 1=1 JOIN (SELECT 3)UT3 on 1=1 -- -
Tips: when learning about SQL injection, it's far easier to just type (or copy-paste) the payload to your SQL console (use virtual machine or sandbox if the query is considered dangerous).
Edit 1:
basic explanation of subquery and union
Subquery: It's basically putting a query inside another query. Subqueries may be inserted in SELECT clause, FROM clause, and WHERE clause.
Example of subquery in FROM clause:
select * from (select 'hello','world','foo','bar')x;
Example of subquery in WHERE clause:
select * from tblsample t1 where t1.price>(select avg(t2.price) from tblsample t2);
Union: concatenating select output, example:
tbl1
+----+--------+-----------+------+
| id | name | address | tele |
+----+--------+-----------+------+
| 1 | Rupert | Somewhere | 022 |
| 2 | John | Doe | 022 |
+----+--------+-----------+------+
tbl2
+----+--------+-----------+------+
| id | name | address | tele |
+----+--------+-----------+------+
| 1 | AAAAAA | DDDDDDDDD | 022 |
| 2 | BBBB | CCC | 022 |
+----+--------+-----------+------+
select * from tbl1 union select * from tbl2
+----+--------+-----------+------+
| id | name | address | tele |
+----+--------+-----------+------+
| 1 | Rupert | Somewhere | 022 |
| 2 | John | Doe | 022 |
| 1 | AAAAAA | DDDDDDDDD | 022 |
| 2 | BBBB | CCC | 022 |
+----+--------+-----------+------+
Edit 2:
further explanation on 3rd payload
In mysql, you can make a 'literal table' by selecting a value. Here is an example:
MariaDB [(none)]> SELECT 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
MariaDB [(none)]> SELECT 1,2;
+---+---+
| 1 | 2 |
+---+---+
| 1 | 2 |
+---+---+
1 row in set (0.00 sec)
MariaDB [(none)]> SELECT 1 firstcol, 2 secondcol;
+----------+-----------+
| firstcol | secondcol |
+----------+-----------+
| 1 | 2 |
+----------+-----------+
1 row in set (0.00 sec)
The purpose of making this 'literal table' is to check how many column the SELECT statement that we inject have. For example:
MariaDB [(none)]> SELECT 1 firstcol, 2 secondcol UNION SELECT 3 thirdcol, 4 fourthcol;
+----------+-----------+
| firstcol | secondcol |
+----------+-----------+
| 1 | 2 |
| 3 | 4 |
+----------+-----------+
2 rows in set (0.07 sec)
MariaDB [(none)]> SELECT 1 firstcol, 2 secondcol UNION SELECT 3 thirdcol, 4 fourthcol, 5 fifthcol;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
As shown above, when UNION is used on two select statement with different number of column, it'll throw an error. Therefore, you can get how many column a SELECT statement when it DOESN'T throw an error.
So, why don't we just use SELECT 1, 2 to generate a 'literal table' with 2 column? That's because the application's firewall block the usage of comma. Therefore we must go the roundabout way and make 2 columned 'literal table' with JOIN query SELECT * FROM (SELECT 1)UT1 JOIN (SELECT 2)UT2 ON 1=1
MariaDB [(none)]> SELECT * FROM (SELECT 1)UT1 JOIN (SELECT 2)UT2 ON 1=1;
+---+---+
| 1 | 2 |
+---+---+
| 1 | 2 |
+---+---+
1 row in set (0.01 sec)
Additional note: MariaDB is the 'free version' of MySQL (since MySQL was sold and made proprietary). MariaDB maintain more or less the same syntax and command as MySQL.

Does memsql really support Ranking Functions?

http://docs.memsql.com/5.0/concepts/window_functions/
I checked the doc linked above and came up with several possible SQL functions but had no luck with any of them. These are just a few:
select row_number() from test;
select row_number() over (order by _id) from test;
select row_number() over {order by _id} from test;
select row_number() over order by _id from test;
select row_number() over (order by _id) as row_num from test;
select row_number over order by _id as row_num from test;
All give me ERROR 1064 (42000): You have an error in your SQL syntax;
MemSQL version is 5.5.8
And of course select _id from test; works fine?
So what is the exact syntax to use? Or is there actually no such thing in MemSQL?
The version string you see is a mysql compatibility version, which I assume you got by doing SELECT version();. To correctly check your MemSQL version, use SHOW VARIABLES WHERE Variable_name = 'memsql_version';.
Window functions are new in MemSQL 5, leading me to believe you aren't running MemSQL 5. That wouldn't be odd, as 5 is still in beta (as of 2016-03-16). You can get the beta here.
In his reply to your question, dnoeth correctly states that queries #2 and #5 are valid. For due diligence, I have ran these queries against my local build of MemSQL, and both of them work.
memsql> create table test(_id int);
Query OK, 0 rows affected (0.01 sec)
memsql> insert into test values (1), (2), (3);
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
memsql> select row_number() over (order by _id) from test;
+----------------------------------+
| row_number() over (order by _id) |
+----------------------------------+
| 1 |
| 2 |
| 3 |
+----------------------------------+
3 rows in set (0.00 sec)
memsql> select row_number() over (order by _id) as row_num from test;
+---------+
| row_num |
+---------+
| 1 |
| 2 |
| 3 |
+---------+
3 rows in set (0.01 sec)
memsql> SHOW VARIABLES WHERE Variable_name = 'memsql_version';
+----------------+-------+
| Variable_name | Value |
+----------------+-------+
| memsql_version | 5.0 |
+----------------+-------+
1 row in set (0.00 sec)

How to get info from VARCHAR column and create new column out of it

I have a problem that I can't figure out.
I have the table where it has column template_name,
in every template, it ends with _US, _EE (aka country).
I have to get that part to a new column that is Country.
Example data:
Template_name Country
Party_package_US US or USA
PARTY_Package_GB GB or England
Random_temp_DE DE or Germany
The output to the new column can be just the three last characters.
I don't know what kind of query I have to do to get that result.
Okay now, what can I do get that result to the new column in table?
UPDATE #silverpop_header
SET MARKET_AREA = a.template_name
FROM #silverpop_header pop
join dw.f_CRM a
ON pop.template_name = a.TEMPLATE_NAME
left join (
select
RIGHT(RTRIM(Template_name), 2) country
from dw.f_CRM )
It is on Sybase
If you just need the last two characters
SELECT
SUBSTRING(Template_name,-2) AS 'Country'
FROM TABLE;
EDIT:
Or as mentioned in the comments:
SELECT
RIGHT(Template_name,2) AS 'Country'
FROM TABLE;
Another way to handle non-2-digit country code.
SELECT Template_name, SUBSTRING_INDEX(Template_name, '_', -1) Country
FROM tbl;
To make this as a full demo. Let me post the full SQLs and output:
SQL:
-- Data prepraration
create table tbl(template_name varchar(200));
insert into tbl values
('Party_package_US'),
('PARTY_Package_GB'),
('Random_temp_DE');
SELECT * FROM tbl;
-- Needed query
SELECT Template_name, SUBSTRING_INDEX(Template_name, '_', -1) Country
FROM tbl;
Output:
mysql> SELECT * FROM tbl;
+------------------+
| template_name |
+------------------+
| Party_package_US |
| PARTY_Package_GB |
| Random_temp_DE |
+------------------+
3 rows in set (0.00 sec)
mysql>
mysql> -- Needed query
mysql> SELECT Template_name, SUBSTRING_INDEX(Template_name, '_', -1) Country
-> FROM tbl;
+------------------+---------+
| Template_name | Country |
+------------------+---------+
| Party_package_US | US |
| PARTY_Package_GB | GB |
| Random_temp_DE | DE |
+------------------+---------+
3 rows in set (0.00 sec)
mysql>
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.8-rc |
+-----------+
1 row in set (0.00 sec)

No Changed Rows Produced by this mySQL update query. Why?

I am at a loss this morning. Maybe my coffee was drugged? Simple problem- get the existing ids into this temp table for an export.
Tables like so:
Table person
+--------+-----------------------+
| id | email |
+--------+-----------------------+
| 142755 | xxxxxxx#xxxxxxxxx.com |
+--------+-----------------------+
Table no_dma
+--------+------------------------+
| person | email |
+--------+------------------------+
| 0 | xxxxxxx#xxxxxxxxx.com |
+--------+------------------------+
Query:
UPDATE
person, no_dma
SET no_dma.person = person.id
WHERE person.email = no_dma.email;
I have verified the existence of at least some matching email addresses in the two tables but the update produces
Query OK, 0 rows affected (9.31 sec)
Rows matched: 0 Changed: 0 Warnings: 0
Clearly I have a little dain bramamge today.
Help me out? What am I doing incorrectly?
// EDIT
Per comments below I made these queries:
mysql> select person, email from no_dma limit 0,1;
+--------+------------------------+
| person | email |
+--------+------------------------+
| 0 | tom_r1989#xxxxxxx.com
+--------+------------------------+
1 row in set (0.00 sec)
mysql> select email from no_dma where email = 'tom_r1989#xxxxxxx.com';
Empty set (0.00 sec)
mysql> select email from no_dma where TRIM(email) = 'tom_r1989#xxxxxxx.com';
Empty set (0.46 sec)
Both tables have email field stored as varchar with collation set to latin1_swedish_ci.
And this this query, WTH?
mysql> SELECT CONCAT('"',email,'"') from no_dma limit 0,3;
+-----------------------+
| CONCAT('"',email,'"') |
+-----------------------+
" |amjor308#xxx.com
" |utt#xxx.com
" |00000000#xxx.com
+-----------------------+
mysql> SELECT email from no_dma limit 0,3;
+--------------------+
| email |
+--------------------+
|+amjor308#xxx.com
|mutt#xxx.com
|000000000#xxx.com
+--------------------+
What is going on there? Looks like newlines but I thought TRIM() handled those?
mysql> SELECT TRIM(email) from no_dma limit 0,3;
+--------------------+
| TRIM(email) |
+--------------------+
|+amjor308#aol.com
|mutt#excite.com
|000000000#aol.com
+--------------------+
3 rows in set (0.00 sec)
UPDATE: FOUND ISSUE
import was done on a Windows generated CSV but mysqlimport was given arg
--lines-terminated-by='\n'
Reimported data works fine.
Sorry to have wasted folks time.
Table no_dma has a trailing space. The data is not the same.
Edit:
SET ANSI_PADDING?
Is it really a space: is ASCII 160
What does a hash or checksum of each value reveal?
What are the string lengths?
The statement is fine, I think. B/c I tested it and it worked.