Which of Database::<QUERY_TYPE> I should use in Kohana 3.3? - database

I need perform query "LOCK TABLE myTable WRITE"
<?php
$db = Database::instance();
$query = 'LOCK TABLE `myTable` WRITE';
$db->query(Database::WHAT_IS_THE_TYPE_SHOULD_SPECIFY_HERE_?, $query);
In framework Kohana 3.3
file ~/modules/database/classes/Kohana/Database.php
implements folowing types:
const SELECT = 1;
const INSERT = 2;
const UPDATE = 3;
const DELETE = 4;
but none of them fit in my case.
Any idea. Thanks.

Google works wonders. http://forum.kohanaframework.org/discussion/6401/lockunlock/p1
You can pass NULL as the first argument:
$db = Database::instance();
$query = 'LOCK TABLE `myTable` WRITE';
$db->query(NULL, $query);
From Kohana: http://kohanaframework.org/3.3/guide-api/Database_MySQL#query
if ($type === Database::SELECT)
{
// Return an iterator of results
return new Database_MySQL_Result($result, $sql, $as_object, $params);
}
elseif ($type === Database::INSERT)
{
// Return a list of insert id and rows created
return array(
mysql_insert_id($this->_connection),
mysql_affected_rows($this->_connection),
);
}
else
{
// Return the number of rows affected
return mysql_affected_rows($this->_connection);
}
As you can see that's why you're able to pass NULL.

Related

CakePHP Query Builder 4.x for SQL INSERT INTO IF NOT EXISTS

This CakePHP Query isn't using the conditional, $subQuery for some reason:
$subQuery = $this->queryFactory->newSelect('table_name')
->select(['id'])
->where(['id' => $id]);
$query = $this->queryFactory->newQuery()
->insert(
['id', 'machine', 'logfile', 'updated', 'time']
)
->into('table_name')
->values([
'id' => $id,
'machine' => $machine['id'],
'logfile' => $logFile,
'updated' => $updateDate,
'time' => $updateTime
])
->where(function (QueryExpression $exp) use ($subQuery) {
return $exp->notExists($subQuery);
});
$query->execute();
...it just inserts record even when it exists, but why?
The above code is only part of the required SQL that looks like this:
IF NOT EXISTS(
SELECT 1
FROM table_name
WHERE id = '$id'
)
INSERT INTO table_name (id, machine, logfile, updated, time)
VALUES (?,?,?,?,?)
ELSE
UPDATE table_name
SET updated = '$var1', time = ' $var2'
WHERE id = '$id';
There is no API that would allow to generate such a statement directly, the query builder isn't ment to generate (and execute) such SQL constructs, it can only compile SELECT, INSERT, UPDATE, and DELETE queries, and while the query expression builder can be used to stitch together arbitrary expressions, it will wrap itself and query objects into parentheses (as it is meant for use in query objects), which would be incompatible with what you're trying to build.
So if you want to run such constructs on SQL level, then you either have to write the SQL manually, or create custom expression classes that can build such constructs. In any case you would have to run the SQL manually then.
Here's a very basic quick & dirty example of such a custom expression class:
namespace App\Database\Expression;
use Cake\Database\ExpressionInterface;
use Cake\Database\ValueBinder;
use Closure;
class IfElseExpression implements ExpressionInterface
{
protected $_if;
protected $_then;
protected $_else;
public function if(ExpressionInterface $expression)
{
$this->_if = $expression;
return $this;
}
public function then(ExpressionInterface $expression)
{
$this->_then = $expression;
return $this;
}
public function else(ExpressionInterface $expression)
{
$this->_else = $expression;
return $this;
}
public function sql(ValueBinder $binder): string
{
$if = $this->_if->sql($binder);
$then = $this->_then->sql($binder);
$else = $this->_else->sql($binder);
return "IF $if $then ELSE $else";
}
public function traverse(Closure $callback)
{
$callback($this->_if);
$this->_if->traverse($callback);
$callback($this->_then);
$this->_then->traverse($callback);
$callback($this->_else);
$this->_else->traverse($callback);
return $this;
}
public function __clone()
{
$this->_if = clone $this->_if;
$this->_then = clone $this->_then;
$this->_else = clone $this->_else;
}
}
It could then be used something like this:
$notExists = (new \Cake\Database\Expression\QueryExpression())
->notExists($subQuery);
$insertQuery = $this->queryFactory->newQuery()
->insert(/* ... */)
//...
;
$updateQuery = $this->queryFactory->newQuery()
->update(/* ... */)
//...
;
$ifElse = (new \App\Database\Expression\IfElseExpression())
->if($notExists)
->then($insertQuery)
->else($updateQuery);
$binder = new \Cake\Database\ValueBinder();
$sql = $ifElse->sql($binder);
$statement = $connection->prepare($sql);
$binder->attachTo($statement);
$statement->execute();
See also
Cookbook > Database Access & ORM > Database Basics > Interacting with Statements
Yes, thanks. My own preference is to avoid the requirement to code the value binding explicitly. Using where(), I can do something like this:
$subQuery = $this->queryFactory->newSelect('table_name')
->select(['id'])
->where(['id' => $id])
->limit(1);
$find = $subQuery->execute()->fetchAll('assoc');
if (!empty($find)) {
$values = [
'id' => $id,
'machine' => $machine,
'logfile' => $logFile,
'updated' => $var1,
'time' => $var2
];
$query = $this->queryFactory->newInsert('table_name', $values);
} else {
$query = $this->queryFactory->newUpdate('table_name')
->set([
'updated' => $someVar,
'time' => $someVar2
])
->where(['id' => $id]);
}
$query->execute();

cakephp code to insert values from forloop in different rows

i am submitting the location from textbox and putting values in comma seprated form like ngp,akola,kanpur.
Now i want if i have 3 values in location textbox then it insert 3 rows in location table one for ngp,second for akola and third for kanpur.
but it also takes last inserted id of user table and post all values in location table.
my location table have fields id,name,user_id.
in user_id column i need the last inserted id of user table and in name column i need to insert all values in table..
please help me to do this..below is my code.
function add() {
if (!empty($this->request->data)) {
$this->User->set($this->data['User']);
$isValidated = $this->User->validates();
if ($isValidated) {
// Generating UUID
if (!empty($this->request->data['User']['company_name'])) {
$this->request->data['User']['is_business'] = 1;
}
if ($this->User->save($this->request->data, array('validate' => false))) {
$lastId = $this->User->id;
$location = implode(',',$this->request->data['User']['location']);
for(i=1;i<=$location;i++){
$this->Location->save($location);
}
}
}
}
}
$lastId = $this->User->id;
$location = explode(',',$this->request->data['User']['location']);
foreach($location as $value){
$data = array();
$data["name"] = $value;
$data["user_id"] = $lastId;
$this->Location->save($data,false);
$this->Location->id = false;
}
Model::saveAll(array $data = null, array $options = array())
$this->request->data['Location'] = explode(',',$this->request->data['User']['location']);
if ($this->User->saveAll($this->request->data, array('validate' => false))){ // ...}

Cakephp save data and read MAX

I'm trying to save data in CakePHP in this way:
get max entry_id from table translations
(SELECT MAX(entry_id) as res FROM translations) + 1
save data into translations table
$translationData = array('entry_id' => $entry_id, 'language_id' => $key, 'text' => $item);
$translation = new Translation();
$translation->set($translationData);
$translation->save();
again get max entry_id
save next set of data
again get max entry_id
save next set of data
Please have a look at my code:
$this->request->data['Product']['name_tr_id'] = $this->Translation->saveTranslations($this->request->data['Product']['name']);
$this->request->data['Product']['description_tr_id'] = $this->Translation->saveTranslations($this->request->data['Product']['description']);
$this->request->data['Product']['seo_title_tr_id'] = $this->Translation->saveTranslations($this->request->data['Product']['seo_title']);
$this->request->data['Product']['seo_keywords_tr_id'] = $this->Translation->saveTranslations($this->request->data['Product']['seo_keywords']);
$this->request->data['Product']['seo_desc_tr_id'] = $this->Translation->saveTranslations($this->request->data['Product']['seo_desc']);
saveTranslations method:
public function saveTranslations($data) {
$entry_id = $this->getNextFreeId();
foreach($data as $key => $item) {
if($item != "") {
$this->create();
$temp['Translation']['entry_id'] = $entry_id;
$temp['Translation']['language_id'] = $key;
$temp['Translation']['text'] = $item;
$this->save($temp);
}
}
return $entry_id;
}
getNextFreeId method:
public function getNextFreeId() {
$result = $this->query("SELECT MAX(entry_id) as res FROM translations");
return $result[0][0]['res'] + 1;
}
I don't know why entry_id have all the time the same value.
After many hours of searching for solution I finally managed to solve the problem in very easy way - just add false parameter in query method:
$this->query("INSERT INTO translations(entry_id, language_id, text) VALUES($entry_id, $key, '$item')", false);
and
$result = $this->query("SELECT SQL_CACHE MAX(entry_id) as res FROM translations", false);

Cloud Datastore API - php - GqlQuery - Binding args

I'm trying to bind some arguments to my GQL query string.
Everything's fine when I run the query without binding anything:
$result = $DB->query_entities("SELECT * FROM kind WHERE fieldName = 4
LIMIT 1");
But I don't know how to bind some arguments. This is how I'm trying to do so:
function query_entities($query_string, $args=[]){
$gql_query = new Google_Service_Datastore_GqlQuery();
$gql_query->setQueryString($query_string);
$gql_query->setAllowLiteral(true);
if( !empty($args) ){
$binding_args = [];
foreach ($args as $key => $value) {
$binding_value = new Google_Service_Datastore_Value();
$binding_value->setIntegerValue($value);
$arg = new Google_Service_Datastore_GqlQueryArg();
$arg->setName($key);
$arg->setValue($binding_value);
$binding_args[] = $arg;
}
$gql_query->setNameArgs($binding_args);
}
$req = new Google_Service_Datastore_RunQueryRequest();
$req->setGqlQuery($gql_query);
return $this->dataset->runQuery($this->dataset_id, $req, []);
}
$exampleValue = 4;
$result = $DB->query_entities("SELECT * FROM kind WHERE fieldName = :fieldName LIMIT 1", ["fieldName" => $exampleValue]);
Or:
function query_entities($query_string, $args=[]){
$gql_query = new Google_Service_Datastore_GqlQuery();
$gql_query->setQueryString($query_string);
$gql_query->setAllowLiteral(true);
if( !empty($args) ){
$binding_args = [];
foreach ($args as $value) {
$binding_value = new Google_Service_Datastore_Value();
$binding_value->setIntegerValue($value);
$arg = new Google_Service_Datastore_GqlQueryArg();
$arg->setValue($binding_value);
$binding_args[] = $arg;
}
$gql_query->setNumberArgs($binding_args);
}
$req = new Google_Service_Datastore_RunQueryRequest();
$req->setGqlQuery($gql_query);
return $this->dataset->runQuery($this->dataset_id, $req, []);
}
$exampleValue = 4;
$result = $DB->query_entities("SELECT * FROM kind WHERE fieldName = :1 LIMIT 1", [$exampleValue]);
This is what I get:
'Error calling POST https://www.googleapis.com/datastore/v1beta2/datasets/age-of-deployment/runQuery: (400) Lexical error at line 1, column 52. Encountered: ":" (58), after : ""' in ...
Cloud Datastore GQL and Python GQL (App Engine) handle argument binding slightly differently.
In this case, you need to use a # instead of a :, for instance:
SELECT * FROM kind WHERE fieldName = #fieldName LIMIT 1
or
SELECT * FROM kind WHERE fieldName = #1 LIMIT 1
Here's the reference documentation for argument binding in Cloud Datastore GQL.

How to delete Model Condition?

I wrote a function which is supposed to return an array of clubs for userId. I don't know why by when I add where(Model_ClubUsers::$USERS_ID,$userId) to dsql() it doesn't set the condition and I have to use addCondition(), but I need it only in this function. Is there a way to delete the condition before function returns?
function getUserClubs($userId){
$columns = array('id',self::$NAME,self::$LOGO_NAME,self::$DESC);
$this->addRelatedEntity('club_users', 'club_users', Model_ClubUsers::$CLUBS_ID, 'inner', 'related');
$this->addField(Model_ClubUsers::$USERS_ID)->relEntity('club_users');
$aAliasedColumns = $this->getAliasedColumns($columns, $this->entity_code);
$this->addCondition(Model_ClubUsers::$USERS_ID,$userId);
$rows = $this->dsql()->field($aAliasedColumns)->do_getAll();
$aResult = array() ;
foreach($rows as $key => $value){
foreach($value as $vKey => $vVal){
if($columns[$vKey]=='id'){
$aRow['key'] = $vVal;
}else if($columns[$vKey]==self::$LOGO_NAME){
$aRow[$columns[$vKey]] = self::$CLUBS_LOGO_PATH.$vVal;
}
else {
$aRow[$columns[$vKey]] = $vVal;
}
}
$aResult[] = $aRow;
}
return $aResult;
}
Please upgrade to 4.2 where the problem is no longer present:
$x=clone $this;
$x->addCondition();
also your syntax can be probably improved with the new 4.2 features.

Resources