These days at NHN we use CUBRID for our services more often than MySQL. This article summarizes the differences between MySQL and CUBRID Database, the knowledge that several departments at NHN have obtained as they have changed their database from MySQL to CUBRID. This document is based on MySQL 5.5 and CUBRID 8.4.1.
The differences can be classified into three types:
- Column Types
- SQL Syntax
- Provided Functions
Differences in Column Types
Case-sensitiveness of Character Types
Basically, MySQL is not case-sensitive for character type values when the query is executed. Therefore, to make the character type be case-sensitive in MySQL, you should add an additional binary keyword when creating a table or a query statement. On the contrary, CUBRID is basically case-sensitive for character type values when the query is executed.
The following example shows how to indicate that a target column is BINARY
when creating a table in MySQL.
INSERT INTO tbl VALUES('Charles'),('blues');
SELECT * FROM tbl WHERE name='CHARLES';
Empty set (0.00 sec)
This example shows how to indicate that a target column is BINARY
when executing a SELECT
statement in MySQL.
+---------+
| name |
+---------+
| Charles |
+---------+
To make CUBRID be case-insensitive, just like MySQL, apply the UPPER()
function or the LOWER()
function to the target column as shown in the following example.
name
======================
'Charles '
'blues '
SELECT * FROM tbl ORDER BY UPPER(name);
name
======================
'blues '
'Charles '
As shown in the example above, when UPPER()
function is not applied the data is returned as they were inserted. When we apply UPPER()
function to the ORDER BY
column we can obtain case-insensitive results. In this case even if there was an index defined on the name
column this index cannot be used by ORDER BY
due to the existence of UPPER()
function, thus no optimization can be applied. If there was no UPPER()
function, ORDER BY
would fetch the data in the order of the defined index. In order to optimize ORDER BY
, you may consider creating a separate column that is totally upper-cased or lower-cased and configuring index in the column.
The following is an example of separately adding the sorting column name2
which is not case-sensitive.
UPDATE tbl SET name2=UPPER(name);
CREATE INDEX i_tbl_name2 ON tbl(name2);
SELECT * FROM tbl ORDER BY name2;
name name2
============================================
'blues ' 'BLUES '
'Charles ' 'CHARLES '
This coming fall we will release a new version of CUBRID under the code name "Apricot" which will introduce function based indexes. Then, you will no longer need to create a separate column and create an index on it. You will be able to do the following:
SELECT * FROM tbl WHERE UPPER(name) = 'CHARLES';
Automatic Type Conversion for Date Type
MySQL is very flexible in converting the type. It accepts character string input in the numeric type and vice versa (number input in the character string type). It also accepts numeric input in the date type.
From version 8.4.0, CUBRID supports flexible type conversion, allowing for character string input in the numeric type and number input in the character string type. However, unlike MySQL, CUBRID does not accept number input in the date type.
The following is an example of inputting numbers in the date type dt
column in MySQL.
mysql> INSERT INTO dt_tbl VALUES (20120515);
mysql> SELECT * FROM dt_tbl;
+------------+
| dt |
+------------+
| 2012-05-15 |
+------------+
1 row in set (0.00 sec)
The following is an example of inputting numbers in the date type dt
column in CUBRID. You can see that an error is returned as a result value when numbers are input in the date type.
csql> INSERT INTO dt_tbl VALUES (20120515);
ERROR: before ' ); '
Cannot coerce 20120515 to type date.
csql> INSERT INTO dt_tbl VALUES ('20120515');
csql> SELECT * FROM dt_tbl;
dt
============
05/15/2012
When an error occurs as a result of executing the date function, MySQL returns NULL
and CUBRID returns an error by default. To make CUBRID return NULL
for such cases, set the value of return_null_on_function_errors
system parameter to yes
.
The following example shows that NULL
is returned when an invalid parameter has been entered in the date function of MySQL.
+------------------+
| YEAR('12:34:56') |
+------------------+
| NULL |
+------------------+
1 row in set, 1 warning (0.00 sec)
The following example shows that an error is returned when an invalid parameter has been entered in the date function of CUBRID when the value of system parameter return_null_on_function_error
has been set to no
which is the default value.
ERROR: Conversion error in date format.
The following example shows that NULL
is returned when an invalid parameter has been entered in the date function of CUBRID when the value of system parameter return_null_on_function_errors
has been changed to yes
.
year('12:34:56')
======================
NULL
Result Value Type of Integer-by-Integer Division
When integer-by-integer division is performed, MySQL prints the output value as a DECIMAL (m, n)
, but CUBRID prints it as a rounded INTEGER
. This is because when each operand is of the same type, the result in CUBRID is printed as that same type. In this case to display the result value as a REAL
number, apply the CAST()
function to any or all operands in the fraction.
The following shows an example of executing integer-by-integer division in MySQL. The result value will be printed as a real number type.
+--------+
| 4/3 |
+--------+
| 1.3333 |
+--------+
mysql> SELECT 4/2;
+--------+
| 4/2 |
+--------+
| 2.0000 |
+--------+
The following shows an example of executing integer-by-integer division in CUBRID. The result value will be printed as an INTEGER
type.
4/3
=============
1
csql> SELECT 4/2;
4/2
=============
2
The following shows an example of executing integer-by-integer division by using the CAST()
function in CUBRID. The result value will be printed as a real number type.
cast(4 as numeric(5,4))/ cast(3 as numeric(5,4))
======================
1.333333333
The following shows an example of executing integer-by-real number division in the CUBRID. Since one of the input values is a real number type, the result value will be printed as a real number (DOUBLE
) type .
4/3.0
======================
1.333333333
Processing SUM result which is larger than the Maximum Value of Input Value Type
How will the result be printed if the result of SUM
is larger than the maximum value of the input value type?
MySQL converts the result of SUM
to a pre-defined large DECIMAL
number type. However, CUBRID processes the result as an overflow error. It means that in CUBRID the type of the input column decides the result type. Therefore, to avoid overflow errors in CUBRID, you should convert (CAST()
) the input column type to a type that can accept the SUM
result value before executing operations.
Converting the type when executing the CAST()
function incurs some additional cost, so I recommend to decide the column type considering the result value of functions you plan to use.
First, configure the same table in MySQL and the CUBRID as follows.
INSERT INTO t VALUES(32767);
INSERT INTO t VALUES (32767);
MySQL successfully prints the value because the result value of executing SUM
is smaller than the result type. However, as the print type is decided by the input type in CUBRID, an overflow error occurs because the resulting value of executing SUM
is larger than the result type.
+-----------+
| sum(code) |
+-----------+
| 65534 |
+-----------+
mysql> SHOW COLUMNS FROM ttt;
+-----------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| sum(code) | decimal(27,0) | YES | | NULL | |
+-----------+---------------+------+-----+---------+-------+
csql> SELECT SUM(code) FROM t;
ERROR: Overflow occurred in addition context.
The following is an example of converting the column type and then executing SUM
in CUBRID. You can see that the value has been successfully printed.
sum( cast(code as integer))
======================
65534
The following is an example of executing SUM
after deciding the column type by considering the SUM result value size in the stage of creating a table in the CUBRID. You can see that the value has been successfully printed.
csql> INSERT INTO t VALUES(32767);
csql> INSERT INTO t VALUES (32767);
csql> SELECT SUM(code) FROM t;
sum(code)
======================
65534
Result Value Type of VARCHAR Type
MySQL and CUBRID both allow for numerical operation when the value of the column that is VARCHAR
type is a string consisting of numbers. In this case, the operation result type is DOUBLE
for both (however, saving a value that needs numerical operation as a string type is not recommended; it is used just for explanation here).
The following is an example of comparing the query result type of the MySQL to that of CUBRID.
mysql> INSERT INTO tbl VALUES('1'),('2'),('3'),('4'),('5');
mysql> CREATE TABLE ttbl AS SELECT SUM(col) FROM tbl;
mysql> SHOW COLUMNS FROM ttbl;
+----------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------+------+-----+---------+-------+
| SUM(col) | double | YES | | NULL | |
+----------+--------+------+-----+---------+-------+
csql> CREATE TABLE tbl(col VARCHAR(10));
csql> INSERT INTO tbl VALUES('1'),('2'),('3'),('4'),('5');
csql> CREATE TABLE ttbl AS SELECT SUM(col) FROM tbl;
csql> ;sc ttbl
<Class Name>
ttbl
<Attributes>
sum(col) DOUBLE
In MySQL, if there is a character (not a number) that exists on the column value, the character is considered as 0 for operation. However, CUBRID prints an error that it cannot convert the character to double type. See the following example.
mysql> SELECT SUM(col) FROM tbl;
+--------+
| SUM(a) |
+--------+
| 15 |
+--------+
csql> INSERT INTO tbl VALUES('a');
csql> SELECT SUM(col) FROM tbl;
ERROR: Cannot coerce value of domain "character varying" to domain "double".
Difference of SQL Syntax
Supporting START WITH … CONNECT BY
CUBRID supports the START WITH … CONNECT BY
syntax which can express the hierarchy that MySQL does not support as a query. This is a part of Oracle SQL compatibility syntax.
As an example, using the following data we will print "managers" and "juniors" by sorting the result values within the same level in the order of "join date". id
is the employee ID of a junior staff and mgrid
is the employee ID of a manager.
INSERT INTO tree VALUES (1,NULL,'Kim', 1963);
INSERT INTO tree VALUES (2,NULL,'Moy', 1958);
INSERT INTO tree VALUES (3,1,'Jonas', 1976);
INSERT INTO tree VALUES (4,1,'Smith', 1974);
INSERT INTO tree VALUES (5,2,'Verma', 1973);
INSERT INTO tree VALUES (6,2,'Foster', 1972);
INSERT INTO tree VALUES (7,6,'Brown', 1981);
MySQL does not support hierarchy statement. Therefore, to print the result value satisfying the above request, you should execute several query statements in the following order.
1) First, print a "level 1" employees whose mgrid
is NULL.
2) Then print the "level 2" employees whose mgrid
is 1.
3) Then print the "level 2" employees whose mgrid
is 2.
4) Then print the level "3 employee" whose mgrid
is 6.
On the contrary, as CUBRID supports the hierarchical queries, a single query statement can be created as follows.
FROM tree
START WITH mgrid IS NULL
CONNECT BY PRIOR id=mgrid
ORDER SIBLINGS BY id;
id mgrid name level
===============================================
1 null Kim 1
3 1 Jonas 2
4 1 Smith 2
2 null Moy 1
5 2 Verma 2
6 2 Foster 2
7 6 Brown 3
The above code means that a parent node (manager) and the child node (junior staff) should be printed in order of the values of child nodes (junior staffs) with the same level in the order of the id
.
Including Disaggregate Item in the SELECT LIST which Includes Aggregate Function
ONLY FULL GROUP BY
When executing the GROUP BY
clause, both MySQL and CUBRID basically allow the disaggregate column that is not included in the GROUP BY
clause to be included in the SELECT
list. However, the disaggregate column not included in the GROUP BY
clause selects the record value which is fetched among various values for the first time. Therefore, note that the value may be different according to the fetch orders of MySQL and CUBRID. For the disaggregate column, it is not clear which proper value should it select among several values. Therefore, enable the ONLY FULL GROUP BY
function to not expose the column that is not included in the GROUP BY
clause to the SELECT
list.
To enable the ONLY FULL GROUP BY
function, for MySQL set the sql_mode
value in the my.conf
configuration file to ONLY_FULL_GROUP_BY
. For CUBRID, set the only_full_group_by
value in the cubrid.conf
configuration file to yes
.
From version 8.3.0 CUBRID supports the only_full_group_by
system parameter. Before 8.3.0, the ONLY FULL GROUP BY
function always ran as if it was enabled.
The following example shows the result of executing the GROUP BY
clause in MySQL and CUBRID while the ONLY FULL GROUP BY
function is enabled.
(dept_no int, name VARCHAR(20) PRIMARY KEY, sales_month int, sales_amount int DEFAULT 100);
INSERT INTO sales_tbl VALUES
(501, 'Stephan', 4, DEFAULT),
(201, 'George' , 1, 450),
(201, 'Laura' , 2, 500),
(301, 'Max' , 4, 300),
(501, 'Chang' , 5, 150),
(501, 'Sue' , 6, 150),
(NULL, 'Yoka' ,4, NULL);
SELECT dept_no, avg(sales_amount) FROM sales_tbl
GROUP BY dept_no ORDER BY dept_no;
dept_no avg(sales_amount)
================================
NULL NULL
201 475
301 300
501 133
When There Is No GROUP BY Clause, Is it possible to Query Even if the Disaggregate Item Exists in the SELECT LIST?
MySQL has an item that uses the aggregate function in the SELECT
list and executes one value that has been fetched initially when there are several values for another item. However, in this case, CUBRID considers that it cannot decide the value and returns an error.
If there is a disaggregate column by the aggregate function in the SELECT LIST
, it means that any value among various values for the column will be randomly selected. Therefore, it is recommended not to execute that kind of query.
Configure identical data in MySQL and CUBRID as shown below.
INSERT INTO tbl VALUES (1,'20000101');
INSERT INTO tbl VALUES (2,'20000102');
INSERT INTO tbl VALUES (3,'20000103');
INSERT INTO tbl VALUES (4,'20000104');
In this case, the following query can be executed for both MySQL and CUBRID.
+----------+-----------------------------------+
| COUNT(a) | DATE_ADD(MAX(b), INTERVAL 10 DAY) |
+----------+-----------------------------------+
| 4 | 2000-01-14 |
+----------+-----------------------------------+
In MySQL, when there are several values for column a, the column value of the record which has been fetched for the first time is calculated. In this case, the value of column a is floating so this processing is not proper.
+----------+----------------------------------+
| COUNT(a) | DATE_ADD(MAX(b), INTERVAL a DAY) |
+----------+----------------------------------+
| 4 | 2000-01-05 |
+----------+----------------------------------+
In CUBRID, when there are several values for column a, CUBRID considers that it cannot determine which record column value must be calculated and returns an error.
ERROR: tbl.a is not single valued. Attributes exposed in
aggregate queries must also appear in the group by clause.
When an error is returned as shown above, if you want to make it executable, change the a to MAX(a)
or MIN(a)
in order to get only one value for the INTERVAL a
as shown below. If the value of a
is always the same, the result of executing this query in MySQL before changing the a
will be same as the result in CUBRID after changing the a
.
count(a) date_add(max(b), INTERVAL max(a) DAY)
=====================================================
4 01/08/2000
Using a Reserved Word as Column Name and Table Name
Both MySQL and CUBRID do not allow reserved words for column name, table name, and alias. To use reserved words for identifiers such as column name, table name, and alias, the reserved words must be enclosed with quotes ("
or `
). In CUBRID, square brackets ([ ]
) are allowed as well as quotes.
Each DBMS supports different reserved words. For example, MySQL does not use ROWNUM
, TYPE
, NAMES
, FILE
, and SIZE
as reserved words, however, CUBRID uses them all. For more details on CUBRID reserved words, see the online manual CUBRID SQL Guide > Reserved Words.
The following example is using reserved words as column names in CUBRID.
CREATE TABLE "names" ("file" VARCHAR(255), "size" INT, "type" CHAR(10));
CREATE TABLE [names] ([file] VARCHAR(255), [size] INT, [type] CHAR(10));
SELECT [file], [size], [type] FROM [names];
Functional Differences
Supporting Descending Index
Technically, in MySQL, you can create a descending (DESC
) index. However, the descending index is not actually created. However, the descending index is actually created in CUBRID.
The following example shows creating the descending index for the ndate
column in the CUBRID.
Note that you can create an index in CUBRID as using the REVERSE
keyword. Then the index is created in the same order of having DESC
in the column.
The following example shows how to use the REVERSE
keyword and the DESC
keyword in order to create indexes for the ndate
column in CUBRID in descending order.
... which is same as...
In MySQL, creating indexes in descending order is not allowed. Therefore, you can create an ascending index after adding an additional column in order to input values in the reverse order. For example, convert the value of DATE"2012-05-18" to the numeric value -20120518 (negative value) and then input an additional column.
The following example shows creating an ascending index for the reverse_ndate
column in MySQL.
1)
2)
3)
4)
However, when you create a descending index in the ndate
column, or when you create the reverse_ndate
column with reverse order values and then create an ascending index, if one is UPDATE
or DELETE
and the other is SELECT
, UPDATE
, or DELETE
and both of indexes are simultaneously scanned, the index scan will be made in reverse to each other. This case increases the possibility of a deadlock so you must note this while creating a descending index.
Both MySQL and CUBRID have a bi-directional link between index nodes. Therefore, the ascending index can be used when the query planner determines that the cost of reverse scan using an ascending index will be lower than the sequential scan using the descending index even if ORDER BY DESC
is performed in the query, The reverse scan takes the advantage only when the number of records to be scanned is relatively small.
The following example shows using an ascending index when ordering in the descending order in CUBRID.
csql> CREATE INDEX i_test_tbl_a ON test_tbl(a);
csql> INSERT INTO test_tbl (a, b) VALUES (10, 'a'), (20, 'b'), (30, 'c'), (40, 'd'), (50, 'e'), (60, 'f'), (70, 'g'), (80, 'h'), (90, 'i'), (100, 'j');
csql> SELECT a FROM test_tbl WHERE a > 70 ORDER BY a DESC;
Supporting ROWNUM
ROWNUM
is a function to number the result rows of the SELECT
query from 1 in the ascending order and used as a column of a table. With ROWNUM
, you can add a serial number for printed records and limit the number of records of the query result by using the conditions of the WHERE
clause.
CUBRID supports ROWNUM
while MySQL does not. So if you want to add a serial number to the records in MySQL, you should use a session variable. Both MySQL and CUBRID support LIMIT … OFFSET
in order to limit the number of records of the query result. However, the following discussion will address ROWNUM
.
The following two examples are used to print serial numbers for the records of the query result.
In MySQL, process ROWNUM
by using a session variable.
mysql> INSERT INTO test_tbl VALUES ('a'), ('b'),('c'),('d');
mysql> SELECT @rownum := @rownum + 1 as rownum, col FROM test_tbl WHERE (@rownum := 0)=0;
+--------+------+
| rownum | col |
+--------+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
+--------+------+
In CUBRID, execute ROWNUM
.
rownum col
============================================
1 'a'
2 'b'
3 'c'
4 'd'
Oracle also supports ROWNUM
. However, in Oracle, ROWNUM
is executed first in the syntax including the GROUP BY
clause and the ORDER BY
clause, and then the GROUP BY
clause and the ORDER BY
clause are executed later. Therefore, the printed ROWNUM
> is not in the sorting order. So, if you want to execute the query including the GROUP BY
clause or the ORDER BY
clause first, make the query as a subquery of the FROM
clause and execute ROWNUM
for that.
The following example shows printing ROWNUM
in the order of ORDER BY
in Oracle.
CUBRID supports the GROUPBY_NUM()
function and the ORDERBY_NUM()
function which produces the result of GROUP BY
and ORDER BY
printed in the order.
In the example of MySQL, since there was no ROWNUM
and a session variable @rownum
has been used, the final order result was used to print the result even though there were the GROUP BY
clause and the ORDER BY
clause. However, since CUBRID uses ROWNUM
, you should use the GROUPBY_NUM()
function and the ORDERBY_NUM()
function if you want to keep the order of printed numbers without using a subquery.
The following two examples show the difference between two cases; one uses GROUPBY_NUM()
function while the other does not. Also it shows limiting the number of result records by using ROWNUM
and then executing the GROUP BY
order in the corresponding records.
WHERE ROWNUM BETWEEN 1 AND 5 GROUP BY host_year;
rownum host_year min(score)
=========================================================
6 2000 '03:41.0'
6 2004 '01:45.0'
The following example shows limiting the number of result records by using GROUPBY_NUM()
for the record set ordered by using GROUP BY
.
GROUP BY host_year HAVING GROUPBY_NUM() BETWEEN 1 AND 5;
groupby_num() host_year min(score)
==================================================
1 1968 '8.9'
2 1980 '01:53.0'
3 1984 '13:06.0'
4 1988 '01:58.0'
5 1992 '02:07.0'
The following two examples show the difference between two cases; one uses the FOR ORDERBY_NUM()
function while the other does not. Also it shows limiting the number of result records by using ROWNUM
and then executing the ORDER BY
order in the corresponding records.
WHERE ROWNUM BETWEEN 3 AND 5 ORDER BY score;
athlete score
============================================
'Thorpe Ian' '01:45.0'
'Thorpe Ian' '03:41.0'
'Hackett Grant' '14:43.0'
The following example shows limiting the number of the result records by using ORDERBY_NUM()
for the record set ordered by using ORDER BY
.
ORDER BY score FOR ORDERBY_NUM() BETWEEN 3 AND 5;
athlete score
============================================
'Luo Xuejuan' '01:07.0'
'Rodal Vebjorn' '01:43.0'
'Thorpe Ian' '01:45.0'
Difference of AUTO_INCREMENT
What should we do if we must know the primary key created after executing INSERT
?
The LAST_INSERT_ID()
function is used to get the last value which has been INSERTED to the column after INSERTING a value to the AUTO_INCREMENT
attribute column within a program connected to the database. For example, you can use it when you want to INSERT
a value in the table where the primary key is included and then insert a foreign key value from another table in the table as the value of the LAST_INSERT_ID()
function. Both MySQL and CUBRID support this function. However, an error may occur in some specific cases, so I recommend you to directly get the AUTO_INCREMENT
value rather than using the LAST_INSERT_ID()
function in CUBRID. Below I will explain these specific cases.
In MySQL or CUBRID, when a record is INSERTED to the table which includes the AUTO_INCREMENT
attribute column, the value of the column is automatically increased by 1.
INSERT INTO tbl (col2) VALUES(1);
INSERT INTO tbl (col2) VALUES(2);
INSERT INTO tbl (col2) VALUES(3);
SELECT LAST_INSERT_ID();
+------------------+
| last_insert_id() |
+------------------+
| 3 |
+------------------+
After executing INSERT
to Table A, if you are trying to INSERT
a foreign key value to Table B (which refers to Table A) by using the LAST_INSERT_ID()
function value and an application or a server is unexpectedly and abnormally terminated, what will happen? (on the assumption that the procedure is one transaction, of course)
In MySQL, the procedure, including all values increased by the AUTO_INCREMENT
, is rolled back. If the AUTO_INCREMENT
value of the record to execute INSERT newly was 3, the AUTO_INCREMENT
value becomes 3 again after transaction rollback. However, in CUBRID, the increase of AUTO_INCREMENT
value is not affected by transaction rollback. Therefore, the existing AUTO_INCREMENT
value of the record was 3, the AUTO_INCREMENT
value becomes 4 after transaction rollback.
In MySQL, you can get the value entered in the column specified as the AUTO_INCREMENT
by using the LAST_INSERT_ID()
function only. However, in CUBRID, you can directly get the AUTO_INCREMENT
value without using the LAST_INSERT_ID()
function. It is just like using the SERIAL object of CUBRID because AUTO_INCREMENT
has been implemented as a SERIAL object in CUBRID. When an AUTO_INCREMENT
column is created in CUBRID, the name of the SERIAL object of the column is specified as "<table name>_ai_<column name>" internally.
The following example shows calculating the next value and the current value on the AUTO_INCREMENT
column in CUBRID.
SELECT <table name>_ai_<column name>.CURRENT_VALUE;
In the current CUBRID version, the LAST_INSERT_ID()
function may malfunction in the following specific cases. Therefore, I recommend that you directly get the AUTO_INCREMENT
value rather than using the LAST_INSERT_ID()
function. The LAST_INSERT_ID()
is one of the session variables that manage the values in each database connection unit. If a broker is switched in CUBRID or if a failover occurs because of master node switch in the HA environment, it may malfunction so the desired value may not be printed. It will be modified later.
In the following example, a session variable has been used as an intermediate storage for getting the next AUTO_INCREMENT
value. For an application, use the variable in the program as an intermediate storage. Note that the SERIAL in CUBRID has the same function as the SEQUENCE in Oracle.
The following example shows executing INSERT
the primary key and the foreign key respectively after getting the NEXT_VALUE
value of the SERIAL.
csql> CREATE TABLE tblFK (colfk INT AUTO_INCREMENT PRIMARY KEY, colfk2 INT, CONSTRAINT fk_col FOREIGN KEY (colfk2) REFERENCES tblPK (col));
At this time, the name of SERIAL created by the tblPK AUTO_INCREMENT
is tblpk_ai_col
. You can check that by executing:
Directly insert the tblPK AUTO_INCREMENT
value in the tblPK
primary key and the tblPK
foreign key. You don't need to save the tblFK colfk
in an additional variable since it is not referred to by the other tables.
csql> INSERT INTO tblPK VALUES (@a,10);
csql> INSERT INTO tblFK(colfk2) VALUES (@a);
The following example shows how to write the code that returns the primary key value when a value executes INSERT
in the tblPK
in the iBatis sqlmaps. For the tblFK
foreign key, use the returned value from the "insert" object.
INSERT INTO tblPK(col, col2) VALUES (#id#, #col2#)
Length Difference of String Functions Such as CHAR_LENGTH
For a string function, MySQL calculates the length based on the number of characters. However, CUBRID calculates it based on the character byte length. This difference depends on the database support of the character set. MySQL supports the character set and calculates the length based on the character set. However, CUBRID does not support the character set and considers all data as bytes, so it calculates the length based on the byte length.
For UTF-8 character set, the byte length of one Korean character is 3 bytes. Therefore, the return value of the CHAR_LENGTH will be three times the number of characters in CUBRID in case of Korean characters. In CUBRID, the functions related to the character length, such as POSITION
, RPAD
and SUBSTR
, use the byte length as the input parameter, not the character length. When specifying the length of CHAR
or VARCHAR
also as creating a table, the byte length is used.
In the second half of this year we will release a new version of CUBRID under the code name "Apricot" with full Unicode support where the calculation will be made based on the character length, not the byte length.
The following example shows the result of executing CHAR_LENGTH
in the CUBRID.
char length('CUBRIDa')
==================
13
Cursor Holdability After Commit while the Record Set Fetch
Cursor holdability is that an application holds the record set of the query result to fetch the next record even after performing an explicit commit or an automatic commit. In this connection, the JDBC specification supports ResultSet.HOLD_CURSORS_OVER_COMMIT
and ResultSet.CLOSE_CURSORS_AT_COMMIT
. Both MySQL and CUBRID ignore the configuration that uses the conn.setHoldability()
function. MySQL always runs as HOLD_CURSORS_OVER_COMMIT
, and CUBRID always runs as CLOSE_CURSORS_AT_COMMIT
.
In MySQL, when
conn.getHoldability()
is called, theCLOSE_CURSORS_AT_COMMIT
value is returned, which is opposite to the current operation. Refer to the source code of mysql-connector-java-5.1.20.tar.gz of http://www.mysql.com/downloads/connector/j/.
In other words, MySQL holds the cursor even if a commit occurs during fetch, and CUBRID closes the cursor when a commit occurs during fetch. Therefore, to hold the cursor while fetching the record set SELECT
in CUBRID 8.4.x or lower versions, set the auto commit mode to FALSE
and fetch the record set while not committing a transaction. (In the new version of CUBRID "Apricot" to be released in the second half of this year, the cursor will be held regardless of commit unless the record set is closed.)
The following schema is used below to demonstrate how cursor holdability works.
INSERT INTO tbl1 VALUES (1),(2),(3),(4);
CREATE TABLE tbl2(a INT);
The following example shows a program that there are four data rows on Table tbl1 while the auto commit is set to true (autocommit=true
) and SELECT
and INSERT
the data to Table tbl2. After executing that, MySQL holds the cursor even when auto commit is executed, so four data will be INSERT
in Table tbl2. On the contrary, CUBRID closes the cursor because of auto commit when INSERT
is executed. Therefore, no more fetch is executed and only one data will be INSERT
in Table tbl2.
stmt=conn.createStatement();
stmt2=conn.createStatement();
String q1 = "SELECT a FROM tbl1";
String q2;
ResultSet rs = stmt.executeQuery(q1);
conn.commit();
while (rs.next())
{
int a = rs.getInt("a");
q2="INSERT INTO tbl2 VALUES ("+a+")";
stmt2.executeUpdate(q2);
}
stmt.close();
stmt2.close();
}
Conclusion
In this article I have reviewed many (but not all) differences between MySQL and CUBRID, which I recommend users to know before they switch from MySQL to CUBRID. It is important to fully understand these differences to successfully apply CUBRID to services.
By Donghyeon Lee, NHN Business Platform DBMS Development Lab
From the author:
"Is your baby a boy?" I am a father who is asked this question even though my little baby is a girl. I will do my best until the day CUBRID becomes a DBMS that is very familiar to users.
References
- MySQL 5.5 Reference Manual: http://dev.mysql.com/doc/refman/5.5/en/create-index.html
- MySQL Performance Blog: http://www.mysqlperformanceblog.com/2006/05/09/descending-indexing-and-loose-index-scan/
- Interface ResultSet (Java Platform SE 7): http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html