I have installed PHP, Apache and MySQL manually on my MacBook and I'm following a book about how to create the table without using phpMyAdmin. My script doesn't seem to be creating the DNS, however, it doesn't throw any exceptions. Any suggestions, guys? Thanks in advance.
This is my code: file name: setup.php
<?php
print("Created.\n"); // This statement prints
$db = new PDO("mysql:host=localhost;dbname=MyBlog", "username", "password");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
print("Created.\n"); // This statement does not print
try {
$queryStr = "CREATE TABLE users (id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40), password VARCHAR(100), email VARCHAR(150))";
$db->query($queryStr);
print("Created.\n");
} catch (PDOException $e) {
echo $e->getMessage();
}
You should write the code where you instatiate and set up the PDO object in the try block. That way you can catch exceptions that occur during connect etc.
Related
The concept:
I have a task which imports some data on the database. The database schema can be changed at any time since it is exported to a folder. So i have to read the database file and create the structure. I would like to do it with TYPO3 API. Before TYPO3 9 i would do something like that:
$sqlQueries = explode(';', file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'myFile.sql'));
foreach ($sqlQueries as $sqlQuery) {
$sqlQuery = trim($sqlQuery);
if (!empty($sqlQuery) && $this->db instanceof DatabaseConnection && method_exists($this->db, 'sql_query')) {
$this->db->sql_query($sqlQuery);
}
}
How do i do that with TYPO3 10?
Best regards
TYPO3 10 has already such functionality and you can find it in the maintenance module unter the
Analyze Database Structure. Thanks to Mathias Brodala i found my solution. (It can always be improved).
In your task you call the SqlReader class in order to extract the statements from the SQL file. The use namespace is the following (As of TYPO3 10)
use TYPO3\CMS\Core\Database\Schema\SqlReader;
Now we have two problems with that
The SQL evaluated and executed by TYPO3 is limited to schemas. For content changes you need a 3rd party library/tool.
It only creates tables and doesn't drop them by default.
The first "problem" it says that you can only perform database structure changes but not the content in it. For that, one could use the QueryBuilder.
The second problem is that the getCreateTableStatementArray function in the SqlReader class does the following:
return $this->getStatementArray($dumpContent, '^CREATE TABLE');
This calls the getStatementArray function and it only returns the CREATE TABLE commands. So if you have a DROP TABLE command in the SQL file, it won't be taken into consideration. For that, we need to create our own function for the getCreateTableStatementArray. So in your Task, create this function:
/**
* #param string $dumpContent
* #return array
*/
public function getCreateTableStatementArray(string $dumpContent): array
{
$sqlReader = GeneralUtility::makeInstance(SqlReader::class);
return $sqlReader->getStatementArray($dumpContent);
}
With this, TYPO3 will not evaluate the statements by command name and it will get all the commands available in the sql file.
Now that we have done that, we need to pass the statements into our custom function to be parsed. So somewhere in your code you get file's content. I have it like this:
/**
* #return bool
* #throws \Exception
*/
public function execute()
{
...
$this->createTableStructure();
...
}
protected function createTableStructure()
{
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$sqlStatements = $this->getCreateTableStatementArray(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'myFile.sql'));
foreach ($sqlStatements as $sqlStatement) {
if (strpos($sqlStatement, ' CHARSET=utf8') !== false) {
$sqlStatement = str_replace(" DEFAULT CHARSET=utf8", "", $sqlStatement);
}
$connection = $connectionPool->getConnectionByName('Default');
try {
$connection->executeUpdate($sqlStatement);
} catch (DBALException $e) {
//Your log here
}
}
}
For this part i got an error that TYPO3 could not read the DEFAULT attribute so i had to remove it.
if (strpos($sqlStatement, ' CHARSET=utf8') !== false) {
$sqlStatement = str_replace(" DEFAULT CHARSET=utf8", "", $sqlStatement);
}
This looks like this in the SQL file:
DROP TABLE IF EXISTS `myTable`;
CREATE TABLE IF NOT EXISTS `myTable` (
`myColumn1` int(10) NOT NULL DEFAULT '0',
`myColumn2` varchar(255) DEFAULT NULL,
`myColumn3` varchar(255) DEFAULT NULL,
`myColumn4` date DEFAULT NULL,
`myColumn5` varchar(255) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Hope it was helpful!
Best regards
Here the Main class :
public class Main {
// JDBC driver name and database URL
static final String JDBC_DRIVER = "org.h2.Driver";
static final String DB_URL = "jdbc:h2:mem:default";
// Database credentials
static final String USER = "sa";
static final String PASS = "";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
// STEP 1: Register JDBC driver
Class.forName(JDBC_DRIVER);
//STEP 2: Open a connection
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
//STEP 3: Execute a query
ScriptRunner sr = new ScriptRunner(conn);
//Creating a reader object
Reader reader = new BufferedReader(new FileReader("C:\\PROJECTS\\src\\main\\resources\\createDatabaseAndUser.sql"));
//Running the script
sr.runScript(reader);
// STEP 4: Clean-up environment
conn.close();
} catch (SQLException se) {
//Handle errors for JDBC
se.printStackTrace();
} catch (Exception e) {
//Handle errors for Class.forName
e.printStackTrace();
} finally {
//finally block used to close resources
try {
if (stmt != null) stmt.close();
} catch (SQLException se2) {
} // nothing we can do
try {
if (conn != null) conn.close();
} catch (SQLException se) {
se.printStackTrace();
} //end finally try
} //end try
System.out.println("Goodbye!");
}
}
createDatabaseAndUser.sql file which located in resourses folder :
CREATE SCHEMA database;
CREATE USER ADMIN PASSWORD 'abc';
I am trying to run my SQL script but receive and ERROR.
Here all output :
Connecting to database...
CREATE SCHEMA database
Error executing: CREATE SCHEMA database.Cause: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error
in SQL statement "CREATE[*] SCHEMA DATABASE"; SQL statement:
CREATE USER ADMIN PASSWORD 'abc'
CREATE SCHEMA database
[42000-199]
Goodbye!
My SQL Dialect is H2 and I use embedded H2 database in Intelij IDEA.
I just begin learning SQL and SQL scripts, so sorry in advance if question is stupid.
It looks like the output from the tool that you use is garbled somehow. There is CREATE[*] SCHEMA DATABASE command ([*] is a marker from H2), but the source SQL is listed as
CREATE USER ADMIN PASSWORD 'abc'
CREATE SCHEMA database
and it is obliviously invalid due to missing semicolon between two commands.
Both places should be the same (with exception for [*] mark) and the error message should be
Syntax error in SQL statement "CREATE USER ADMIN PASSWORD 'abc'
CREATE[*] SCHEMA DATABASE "; SQL statement:
CREATE USER ADMIN PASSWORD 'abc'
CREATE SCHEMA database [42000-199]
So you ether have a missing semicolon in your source file, or this tool removes it. Actually you don't need to use the third-party tool, you can execute the script directly in H2:
Statement st = conn.createStatement();
st.execute("RUNSCRIPT FROM 'C:\\PROJECTS\\src\\main\\resources\\createDatabaseAndUser.sql'");
I have SQL code that executes CREATE TABLE and DROP TABLE in the same query. When I run it, it prints bool(false) meaning error. Can it be done in one query?
$dbh = new PDO("sqlite::memory:");
$stmt = $dbh->prepare("create table a ( i int, j int);drop table a");
var_dump($stmt);
I don't know why but it works if I try it again.
You need to execute your query
Like this :
$stmt ->execute();
And yes you can create and delete a table in the same query.
You can maybe try this to catch an error, it will help you
try
{
$db = new PDO('sqlite::memory');
echo "SQLite created in memory.";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
I created a module and want to used core write and read function to insert,update,delete or select database value with condition, how can I do it without using SQL?
Example:
$customer_id=123
Model=(referral/referral)
SELECT
$collection3 = Mage::getModel('referral/referral')->getCollection();
$collection3->addFieldToFilter('customer_id', array('eq' => $customer_id));
foreach($collection3 as $data1)
{
$ref_cust_id.= $data1->getData('referral_customer_id');
}
INSERT
$collection1= Mage::getModel('referral/referral');
$collection1->setData('customer_id',$customer_id)->save();
DELETE,UPDATE(with condition)=???
Suppose, I have a module named mynews.
Here follows the code to select, insert, update, and delete data from the news table.
INSERT DATA
$data contains array of data to be inserted. The key of the array should be the database table’s field name and the value should be the value to be inserted.
$data = array('title'=>'hello there','content'=>'how are you? i am fine over here.','status'=>1);
$model = Mage::getModel('mynews/mynews')->setData($data);
try {
$insertId = $model->save()->getId();
echo "Data successfully inserted. Insert ID: ".$insertId;
} catch (Exception $e){
echo $e->getMessage();
}
SELECT DATA
$item->getData() prints array of data from ‘news’ table.
$item->getTitle() prints the only the title field.
Similarly, to print content, we need to write $item->getContent().
$model = Mage::getModel('mynews/mynews');
$collection = $model->getCollection();
foreach($collection as $item){
print_r($item->getData());
print_r($item->getTitle());
}
UPDATE DATA
$id is the database table row id to be updated.
$data contains array of data to be updated. The key of the array should be the database table’s field name and the value should be the value to be updated.
// $id = $this->getRequest()->getParam('id');
$id = 2;
$data = array('title'=>'hello test','content'=>'test how are you?','status'=>0);
$model = Mage::getModel('mynews/mynews')->load($id)->addData($data);
try {
$model->setId($id)->save();
echo "Data updated successfully.";
} catch (Exception $e){
echo $e->getMessage();
}
DELETE DATA
$id is the database table row id to be deleted.
// $id = $this->getRequest()->getParam('id');
$id = 3;
$model = Mage::getModel('mynews/mynews');
try {
$model->setId($id)->delete();
echo "Data deleted successfully.";
} catch (Exception $e){
echo $e->getMessage();
}
In this way you can perform select, insert, update and delete in your custom module and in any magento code.
Source: http://blog.chapagain.com.np/magento-how-to-select-insert-update-and-delete-data/
UPDATE is basically the combination of SELECT and INSERT. You load a collection, iterate over them setting the values as needed, then call ->save() on each model.
DELETE is handled directly via the ->delete() functon of models. So either load a single model or iterate over a SELECTed collection of them and call ->delete()
(Not that due to the iteration, this is not the 'fastest' way of doing these operations on collections (because each one is going to generate a new query, instead of a single query that handles multiple deletes at once), but the performance is fine for either small data sets/SELECTs (less than 1k?) or for things that you don't do very often (like importing or updating prices ok 10k products once per day).
FOR UPDATE
$new=$this->getRequest()->getParams();
$id=$new['id'];
$name=$new['name'];
$con=Mage::getModel('plugin/plugin')->load($id);
$con->setData('name',$name)->save();
echo "Update Success";
FOR DELETE
$id = $this->getRequest()->getParam('id');
$model = Mage::getModel('plugin/plugin');
$model->setId($id)->delete();
echo "Data deleted successfully.";
You can use select query like this also. its very easy.
$salesInvoiceCollection_sql = "SELECT `entity_id` , `increment_id`,`order_id`
FROM `sales_flat_invoice`
WHERE `erp_invoice_id` = 0
ORDER BY `entity_id`
DESC limit 1000";
$salesInvoiceCollection = Mage::getSingleton('core/resource')->getConnection('core_read')->fetchAll($salesInvoiceCollection_sql);
If you want to delete with condition based on collection you can use addFieldToFilter, addAttributeToFilter
$model = Mage::getModel('mynews/mynews')->getCollection();
try {
$model->addAttributeToFilter('status', array('eq' => 1));
$model->walk('delete');
echo "Data deleted successfully.";
} catch (Exception $e){
echo $e->getMessage();
}
Sorry for my English first of all. I have a problem and need help.
I have a simple tool made by myself on c#. This tool makes connect to local or remote firebird server (v.2.5). And my tool can create specified .fdb file (database) somewhere on the server.
Also I have a file with SQL statements (create table, triggers and so on). I want to execute this file after database was created. Executing this file will fill structure of user database - not data, only structure.
But then I try to execute my SQL script - firebird server returns a
SQL error code = -104 Token unknown line xxx column xxx.
That's the line on this CREATE TABLE SQL statement, for example:
CREATE TABLE tb1
(
col1 INTEGER NOT NULL,
col2 VARCHAR(36)
);
/* This next create statement causes an error */
CREATE TABLE tb2
(
col1 INTEGER NOT NULL,
col2 VARCHAR(36)
);
If I will leave only one create statement in my file - all will be good... I don't know how I explained (it's clear or not)) - another words - why can't I execute full query with many create statements in one transaction? There is my main method which executes query:
public static string Do(string conString, string query)
{
using (FbConnection conn = new FbConnection())
{
try
{
conn.ConnectionString = conString;
conn.Open();
FbTransaction trans = conn.BeginTransaction();
FbCommand cmd = new FbCommand(query, conn, trans);
cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.ToString());
return "Transaction Fail";
}
}
return "Transaction Commited";
}
There is a query is my SQL file.
As Victor already stated in his final comment, you can use the FBScript class for batch execution.
I was just confronted with the same task. This question pointed me in the right direction but i had to do some further digging.
I this example, the source of the statements is a external script file:
private void ExecuteScript(FbConnection myConnection, string scriptPath) {
if (!File.Exists(scriptPath))
throw new FileNotFoundException("Script not found", scriptPath);
FileInfo file = new FileInfo(scriptPath);
string script = file.OpenText().ReadToEnd();
// use FbScript to parse all statements
FbScript fbs = new FbScript(script);
fbs.Parse();
// execute all statements
FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
fbe.Execute(true);
}
This will work fine, but you may wonder why this whole thing isn't surrounded by a transaction. Actually there is no support to "bind" FbBatchExecution to a transaction directly.
The first thing i tried was this (will not work)
private void ExecuteScript(FbConnection myConnection, string scriptPath) {
using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
if (!File.Exists(scriptPath))
throw new FileNotFoundException("Script not found", scriptPath);
FileInfo file = new FileInfo(scriptPath);
string script = file.OpenText().ReadToEnd();
// use FbScript to parse all statements
FbScript fbs = new FbScript(script);
fbs.Parse();
// execute all statements
FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
fbe.Execute(true);
myTransaction.Commit();
}
}
This will result in an exception stating: "Execute requires the Command object to have a Transaction object when the Connection object assigned to the command is in a pending local transaction. The Transaction property of the Command has not been initialized."
This means nothing more than that the commands that are executed by FbBatchExecution are not assigned to our local transaction that is surrounding the code block. What helps here is that that FbBatchExecution provides
the event CommandExecuting where we can intercept every command and assign our local transaction like this:
private void ExecuteScript(FbConnection myConnection, string scriptPath) {
using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
if (!File.Exists(scriptPath))
throw new FileNotFoundException("Script not found", scriptPath);
FileInfo file = new FileInfo(scriptPath);
string script = file.OpenText().ReadToEnd();
// use FbScript to parse all statements
FbScript fbs = new FbScript(script);
fbs.Parse();
// execute all statements
FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
fbe.CommandExecuting += delegate(object sender, CommandExecutingEventArgs args) {
args.SqlCommand.Transaction = myTransaction;
};
fbe.Execute(true);
// myTransaction.Commit();
}
}
Note that i have uncommented the myTransaction.Commit() line. I was a little bit surprised by this behavior, but if you keep that line the transaction will throw an exception stating that it has already been committed. The bool parameter fbe.Execute(true) is named "autoCommit", but changing this to false seems to have no effect.
I would like some feedback if you see any potential issues with assigning the local transaction this way, or if it has any benefits at all or could as well be omitted.
Probably error in launching two create statements in one batch. Would it work if you break it to separate queries? Does it work in your SQL tool?