I have some MySQL scripts that are needed for recreating a database. They work fine when I execute them on the command line using the mysql command.
Now I wrote a Java class that should execute these scripts using a JDBC connection to the MySQL database.
One line in a "create table"-statement in the script is:
registration_date DATETIME DEFAULT CURRENT_TIMESTAMP
This line however won't be executed using the JDBC-MySQL connection. I get the error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Invalid default value for 'registration_date'
The relevant method is shown below. sqlScriptPathpoints to the folder containing the sql scripts. The connectionString has this content: "jdbc:mysql://localhost:3306/testDb?useUnicode=yes&characterEncoding=UTF-8&allowMultiQueries=true"
public static void recreate(String connectionString, String dbUser, String dbPass, String sqlScriptPath) throws Exception {
// Find and filter sql scripts
File file = new File(sqlScriptPath);
File[] scripts = file.listFiles(new FileFilter() {
#Override
public boolean accept(File file) {
return file.getName().endsWith(".sql");
}
});
List<File> scriptsList = Arrays.asList(scripts);
Collections.sort(scriptsList);
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(connectionString, dbUser, dbPass);
// Load each script and apply it
for (File f : scriptsList) {
System.out.println("Importing script: " + f);
List<String> lines = Files.readAllLines(Paths.get(f.getAbsolutePath()), Charset.forName("UTF-8"));
StringBuilder sb = new StringBuilder();
for (String line : lines) sb.append(line).append("\n");
String sqlStatement = sb.toString();
System.out.print(sqlStatement);
Statement st = conn.createStatement();
st.execute(sqlStatement);
st.close();
}
}
And the relevant part of the script:
CREATE TABLE user
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
username VARCHAR(255),
password VARCHAR(255),
age_group INT,
registration_date DATETIME DEFAULT CURRENT_TIMESTAMP
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
What is the problem here?
I inherited a Java test harness for a MySQL database that was failing with this error on a datetime column defined as NOT NULL with no default defined. I added DEFAULT NOW() and it worked fine after that.
Related
I am facing issue in saving string values in one of the fields of my domain
My Domain is
#Entity
#Table(name = "users")
class User {
#Id
#NotNull
Long id
#NotNull
String uuid
#NotNull
String firstName
}
I am pulling the data from my main mysql database and saving it into another database.
resultSet = statement.executeQuery(userQuery)
while (resultSet.next()) {
User user = new User()
user.id = resultSet.getLong("a.id")
user.uuid = resultSet.getString("a.uuid")
user.firstName = resultSet.getString("b.first_name") // exception occurs here
userRepository.save(user)
}
Some of my data is getting saved but when data from my main database contains user with
firstname = ऋषभ (Name in Hindi Language) then it throws exception.
Note - Only essential codes i mentioned here query execution database connection everything is running fine only facing issue in setting data in user.firstName only when my query result contains string with different language.
ALTER TABLE user MODIFY first_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
I'm having trouble reading a Model from db using ActiveJDBC.
Basically, i'm doing ModelClass.findFirst(...) and a SQLException pops up. There seem to be no problems if the timestamp field is non-zero.
Said Model has a mysql timestamp (tried also datetime) field with zero / null value in it. This example is a timestamp with value '0000-00-00 00:00:00'. Model object is populated without errors if i update the value to a real date/time.
Caused by: java.sql.SQLException: Value '10151payment100.0012002017-01-16 02:06:530000-00-00 00:00:002017-01-16 03:36:43noFirst Last
+358 40 123456b989e4dce9e639eaadbed3b64e2c3eb' can not be represented as java.sql.Timestamp
My question is - i need to store an arbitrary date+time in this column, and for convenience reasons it should be null or zero if a value has not been stored. Is this a possible combination with ActiveJDBC?
EDIT: A minimal example to reproduce below.
Table
CREATE TABLE test (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
ts timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into test (id) values (1);
Model source
import org.javalite.activejdbc.Model;
import org.javalite.activejdbc.annotations.Table;
#Table("test")
public class Test extends Model {
}
Main class
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.javalite.activejdbc.Base;
public class ActiveJDBCTest {
private HikariDataSource dbds;
public ActiveJDBCTest() {
try {
init();
} catch (Exception e) {
System.out.println(e);
}
}
public void init() throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
dbds = new HikariDataSource();
dbds.setJdbcUrl("jdbc:mysql://localhost:3306/test" +
"?useSSL=false" +
"&characterEncoding=UTF-8");
dbds.setUsername("test");
dbds.setPassword("test");
dbds.setConnectionInitSql("SET ##session.time_zone = '+00:00'");
Base.open(dbds);
Test first = Test.findFirst("id = ?", 1);
Base.close();
}
public static void main(String[] args) {
new ActiveJDBCTest();
}
}
Result (please see embedded image for actual exception message - null characters?)
org.javalite.activejdbc.DBException: java.sql.SQLException: Value '10000-00-00 00:00:00' can not be represented as java.sql.Timestamp
Result
Without a full stack trace and DDL, I can only see that you have the following value in your column:
10151payment100.0012002017-01-16 02:06:530000-00-00 00:00:002017-01-16 03:36:43noFirst Last
+358 40 123456b989e4dce9e639eaadbed3b64e2c3eb
The MySQL driver is telling you that it can not be represented as java.sql.Timestamp. I think you some sort of data corruption issue. I do not think it is related to ActiveJDBC.
Ohh hell, i'm sorry for wasting your time. I apparently figured it out.
The underlying db has at some point changed from mysql to mariadb - it's some driver incompatibility while using mysql connector/j with mariadb. Using mariadb driver makes the problem go away.
I'm using Eclipse EE, Tomcat 6 server connected to MySQL server on win7.
I was able to connect to a database through JSP and send commands like SELECT and DESCRIBE but if I try to create a table the JSP code will simply not run!
Why is that?
(Checked my SQL codes on the MySQL command line and it worked. )
JSP error:
org.apache.jasper.JasperException: An exception occurred processing JSP page /index.jsp at
JSP Coding:
try // DB login
{
String connectionURL = "jdbc:mysql://localhost/ofir";
Class.forName("com.mysql.jdbc.Driver").newInstance();
con = DriverManager.getConnection(connectionURL, "root", "");
stmt = con.createStatement();
connected = true;
}
catch(Exception ex)
{
out.println("Unable to connect to database.");
connected = false;
}
rs = stmt.executeQuery("CREATE table users (fname varchar(50), nname varchar(20), pass varchar(50), email varchar(50), gender boolean, age int(3), region varchar(10), notes varchar(1000))"); // Line of the error
*To be noted about the code- all variables are declared globally using ' <%! '
For CREATE TABLE, we have to use stmt.executeUpdate(sql) . Not stmt.executeQuery(sql)
I have made a tiny software tool that allows me to display or run SQL generated from NHibernate. I made this because hbm2ddl.auto is not recommended for production.
I have one problem: when I generate the SQL I always get the infamous Index column unquoted, because I need .AsList() mappings. This prevents me to run the SQL.
In theory, if I had an XML configuration of NHibernate I could use hbm2ddl.keywords tag, but unfortunately since my tool is designed as a DBA-supporting tool for multiple environments, I must use a programmatic approach.
My approach (redundant) is the following:
private static Configuration BuildNHConfig(string connectionString, DbType dbType, out Dialect requiredDialect)
{
IPersistenceConfigurer persistenceConfigurer;
switch (dbType)
{
case DbType.MySQL:
{
persistenceConfigurer =
MySQLConfiguration
.Standard
.Dialect<MySQL5Dialect>()
.Driver<MySqlDataDriver>()
.FormatSql()
.ShowSql()
.ConnectionString(connectionString);
requiredDialect = new MySQL5Dialect();
break;
}
case DbType.MsSqlAzure:
{
persistenceConfigurer = MsSqlConfiguration.MsSql2008
.Dialect<MsSqlAzure2008Dialect>()
.Driver<SqlClientDriver>()
.FormatSql()
.ShowSql()
.ConnectionString(connectionString);
requiredDialect = new MsSqlAzure2008Dialect();
break;
}
default:
{
throw new NotImplementedException();
}
}
FluentConfiguration fc = Fluently.Configure()
.Database(persistenceConfigurer)
.ExposeConfiguration(
cfg => cfg.SetProperty("hbm2ddl.keywords", "keywords")
.SetProperty("hbm2ddl.auto", "none"))
.Mappings(
m => m.FluentMappings.AddFromAssemblyOf<NHibernateFactory>());
Configuration ret = fc.BuildConfiguration();
SchemaMetadataUpdater.QuoteTableAndColumns(ret);
return ret;
}
...
public static void GenerateSql(MainWindowViewModel viewModel)
{
Dialect requiredDialect;
Configuration cfg = BuildNHConfig(viewModel.ConnectionString, viewModel.DbType.Value, out requiredDialect);
StringBuilder sqlBuilder = new StringBuilder();
foreach (string sqlLine in cfg.GenerateSchemaCreationScript(requiredDialect))
sqlBuilder.AppendLine(sqlLine);
viewModel.Sql = sqlBuilder.ToString();
}
Explanation: when I want to set the ViewModel's SQL to display on a TextBox (yea, this is WPF) I initialize the configuration programmatically with connection string given in ViewModel and choose the dialect/provider accordingly. When I Fluently Configure NHibernate I both set hbm2ddl.keywords (tried both auto-quote and keywords, this being the default) and, following this blog post, I also use the SchemaMetadataUpdater.
The result is that I'm always presented with SQL like
create table `OrderHistoryEvent` (Id BIGINT NOT NULL AUTO_INCREMENT, EventType VARCHAR(255) not null, EventTime DATETIME not null, EntityType VARCHAR(255), Comments VARCHAR(255), Order_id VARCHAR(255), Index INTEGER, primary key (Id))
where the guilty Index column is not quoted.
The question is: given a programmatic and fluent configuration of NHibernate, how do I tell NHibernate to quote any reserved word in the SQL exported by GenerateSchemaCreationScript?
I have found a workaround: when I generate the update script (the one that runs with hbm2ddl.auto=update) the script is correctly quoted.
The infamous Index column has been already discussed and from my findings it's hardcoded in FNH (ToManyBase.cs, method public T AsList()).
Since the update script is a perfectly working creational script on an empty database, changing the code to generate an update script on an empty DB should equal generating a creational script.
This happens only because I want to generate the script on my own. There is probably a bug in NHibernate that only activates when you call GenerateSchemaCreationScript and not when you let your SessionFactory build the DB for you
I have created a local H2 database which I always opened in MySQL mode to insert data. Now, I want to export it with SCRIPT, in order to import it with phpMyAdmin on a remote MySQL database on a remote server. I get the following:
SET LOCK_MODE 3;
;
CREATE USER IF NOT EXISTS SA SALT '...' HASH '...' ADMIN;
CREATE CACHED TABLE PUBLIC.RAWVALUEITEM(
LANGUAGE VARCHAR(2) NOT NULL SELECTIVITY 1,
RAWVALUE VARCHAR(40) NOT NULL SELECTIVITY 99,
STRIPPED VARCHAR(40) NOT NULL SELECTIVITY 96
);
...
Unfortunately, phpMyAdmin import is not happy:
#1193 - Unknown system variable 'LOCK_MODE'
When I manually remove the set instruction, I get further errors:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF NOT EXISTS SA SALT '...' HASH '...' at line 1
The code I use to export the database as a script is:
public static final String DB_DIR_LOCATION = "E:/Temp/FWDB/";
public static final String H2_CONNECTION = "jdbc:h2:file:"
+ DB_DIR_LOCATION + "FWDB_PHP_TEST" + "Mode=MySQL;IFEXISTS=TRUE";
public static void main(String[] args) throws SQLException {
Connection conn = DriverManager.
getConnection(H2_CONNECTION, "sa", "");
PreparedStatement ps;
ps = conn.prepareStatement("SCRIPT TO 'E:/Temp/FWDB/FWDB_EXPORT.gz' "
+ "COMPRESSION GZIP");
ps.execute();
}
How can generate a script from my DB which will be imported successfully by phpMyAdmin on my remote server?
The SQL script generated by the SCRIPT TO command is not cross-platform. A better solution might be to use a database tool such as the SQuirreL DB Copy Plugin or another database tool.