TYPO3 alter table with Querybuilder - typo3

How can you use the TYPO3 9 Querybuilder to execute an "ALTER TABLE" command?
ALTER TABLE foo
DROP INDEX bar;
This class should be used to execute the query:
use TYPO3\CMS\Core\Database\ConnectionPool;
...
$table = 'foo';
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
Or is it necessary to instantiate another database object, which e.g. derives from the Doctrine\DBAL\Schema\Schema class.

This should do the Job:
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
// ...
GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('foo')
->exec('ALTER TABLE foo DROP INDEX bar;');
The documentation warns about using queries outside repositories:
https://docs.typo3.org/m/typo3/book-extbasefluid/master/en-us/6-Persistence/3-implement-individual-database-queries.html

Give it try, this may be helpful to you. However, I have never tried to Alter table command before (Never required!!)
$connection = $this->objectManager->get(ConnectionPool::class)->getConnectionForTable($table);
$statement = $this->objectManager->get(
\Doctrine\DBAL\Statement::class
'ALTER TABLE foo DROP INDEX bar',
$connection
);
$query = $this->createQuery();
$query->statement($statement);

Another solution would be the usage of the Doctrine Schema Manager for such cases:
use \TYPO3\CMS\Core\Utility\GeneralUtility;
use \TYPO3\CMS\Core\Database\ConnectionPool;
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('foo');
$connection->getSchemaManager()->dropIndex('bar', 'foo');

Related

How to migrate legacy function exec_SELECT_mm_query to Doctrine based Querybuilder / Connection in TYPO3

Assume the following code snippet:
$res = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query(
$foreign . '.*', $local, $mm, $foreign, 'AND ' . $local . '.uid=' . $constraintUid);
while ($r=$GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
...
$foreign / foreign: name of foreign DB table
$local / local: name of local DB table
$mm / mm : name of relation DB table (typically somethingorother_mm)
$constraintUid / constraintUid: some uid
I would like to migrate code to TYPO3 9 using the Doctrine based database functions.
The above code gets converted to the following SQL statement:
SELECT foreign.* FROM local,mm,foreign
WHERE local.uid=mm.uid_local
AND foreign.uid=mm.uid_foreign
AND local.uid = constraintUid
see exec_SELECT_mm_query:
Parameters:
string $select Field list for SELECT
string $local_table Tablename, local table
string $mm_table Tablename, relation table
string $foreign_table Tablename, foreign table
string $whereClause Optional additional WHERE clauses put in
the end of the query. ...
...
My suggestion would be:
$foreign = 'a';
$mm = 'mm';
$local = 'b';
$item = 1;
/** #var \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder */
$queryBuilder = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
\TYPO3\CMS\Core\Database\ConnectionPool::class
)->getQueryBuilderForTable($foreign);
$expr = $queryBuilder->expr();
/** #var \Doctrine\DBAL\Driver\Statement $rows */
$rows = $queryBuilder
->select('foreign.*')
->from($foreign, 'foreign')
->innerJoin('foreign', $mm, 'mm', $expr->eq('foreign.uid', 'mm.uid_foreign'))
->innerJoin('mm', $local, 'local', $expr->eq('mm.uid_local', 'local.uid'))
->where(
$expr->eq('local.uid', $queryBuilder->createNamedParameter($item, \PDO::PARAM_INT))
)
->execute();
while (($row = $rows->fetch()) != null) {
}

Perl Mojolicious Model

I am creating a
Mojolicious
application but I can't understand the documentation for creating a model.
Could someone provide an example of how to create a model, run a raw SQL query and get the results in a controller to pass to the view?
I am thinking of something like this:
Model
package LS::Model::Dt;
use Mojo::Base;
use DBI;
# Here is what I don't understand
# Do I need to create a subroutine that connects to the database like this?
sub connect_db {
my $user = 'user_sql';
my $pass = 'pass_sql';
my $connection = "dbi:Sybase:server=db.sql-srv.com;database=Adventure";
my $dbh = DBI->connect($connection, $user, $pass) or die 'Cannot connect';
}
sub queries{
my $query_selectall = "select * from foo";
my $all_query = $dbh->selectall_arrayref($query_selectall, {Slice => {}});
}
Controller
package LS::Controller::Home;
use Mojo::Base 'Mojolicious::Controller';
use LS::Model::Dt
sub home {
my $self = shift;
# Somehow get the query results here
my $query_res = #somehow get the query results here
$self->render(res=>$query_res);
}
1;
Later edit: I have managed somehow via this tutorial:
http://oliverguenther.de/2014/04/applications-with-mojolicious-part-four-database-schemas-with-dbixclass/
Github code for when you are now sure where the author is creating a file is available here:
https://github.com/oliverguenther/Moblo
If you encounter problems also check this:
Mojolicious Deploying database schema

How to call Postgres function in DBIx::Class

I'm currently playing around with DBIx::Class and I'm wondering how to call an existing Postgres function in a certain db schema using DBIx.
My DBI code:
my $table = $self->{dbh}->quote_identifier(
undef,
'foo',
'myFunction'
);
my $sqlst = qq{ SELECT foobar FROM $table($some_data); };
The things I found so far, would be to call said function using the dbh object retrieved from my DBIx::Class::Schema object:
my $return_data = {};
my $sql = qq{SELECT foobar FROM "foo"."myFunction"($some_data)};
$self->{schema}->storage->dbh_do( sub {
my ($storage, $dbh) = #_;
$menu_list = $dbh->selectrow_hashref(
$sql,
{ slice => {} }
);
});
Is there a better/easier solution than this?
I also stumbled upon DBIx::ProcedureCall, but I couldn't get it to work when using a DB schema.
Any help is much appreciated!
If you want to use SQL Functions as Table Sources, it should be possible to create a virtual DBIx::Class::ResultSource::View like this:
package MyApp::Schema::Result::MyFunction;
use base qw/DBIx::Class::Core/;
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
__PACKAGE__->table('myFunction');
__PACKAGE__->result_source_instance->is_virtual(1);
__PACKAGE__->result_source_instance->view_definition(
'SELECT foobar FROM "foo"."myFunction"(?)'
);
__PACKAGE__->add_columns(
'foobar' => {
data_type => 'varchar',
},
);
The view can be used like this:
my $rs = $schema->resultset('MyFunction')->select({}, {
bind => [ 'arg' ],
});
This will create a subquery that isn't really necessary:
SELECT me.foobar FROM (SELECT foobar FROM "foo"."myFunction"(?)) me
But I think it should work.

Perl - CGI::Application - Create session variables from database

I have a bunch of configuration variables stored within a database, key value pairs accessable via the following query:
select * from conf_table;
I want to load these key/value pairs into a CGI::Applicaiton session. At the moment this is manually done (so not from database, but hardcoded) via
$self->session->param( NAME => VALUE );
For a bunch of key value pairs. Is there a more sensible way do to this with DBI and some form of loop?
Thanks
You mean something like this?
my $sth = $dbh->prepare("select key, value from mytable");
$sth->execute;
$sth->bind_columns(\(my ($key, $value)));
while ($sth->fetch) {
$self->session->param($key => $value);
}
DBI has some convenience methods that make this sort of work simpler. Try selectall_arrayref:
my $configs = $dbh->selectall_arrayref(
'SELECT * FROM conf_table',
{ Slice => {} }, # make each row a hash
);
$self->session->param($_->{key} => $_->{value}) for #$configs;

Translating a query to use Zend_Db_Select

I'm having some problems translating this query to use ZF's Zend_Db_Select:
SELECT b.id, b.title, b.description
FROM memberships AS m
JOIN blogs AS b ON b.id = m.blog_id
WHERE m.user_id = ?
ORDER BY m.created
LIMIT 0, 30
(this query works and returns results)
Memberships is a link table between blogs and users. It's a simple | id | blog_id | user_id | affair.
Here's what I have so far:
// $table = Zend_Db_Table instance, $id = a user id
$select = $table->select()
->from(array('m' => 'memberships'), array('b.id', 'b.title', 'b.description'))
->join(array('b' => 'blogs'), 'b.id = m.blog_id')
->where('m.user_id = ?', (int) $id)
->order('m.created DESC')
->limit(0, 30);
This is the (strange (to me)) error I'm getting:
#0: Select query cannot join with another table
Occurred on line 211 of D:\...\library\Zend\Db\Table\Select.php.
Thanks for your help.
You could also still use the traditional $model->select() object by adding setIntegrityCheck(false), like so.
$select = $table->select()
->setIntegrityCheck(false)
->from(array('m' => 'memberships'), array('b.id', 'b.title', 'b.description'))
->join(array('b' => 'blogs'), 'b.id = m.blog_id')
->where('m.user_id = ?', (int) $id)
->order('m.created DESC')
->limit(0, 30);
This disables the check that is throwing the exception:
#0: Select query cannot join with another table
When retrieved from your table object, the statement will be limited to that table I think. The Zend_Db_Table::select() methods returns a Zend_Db_Table_Select object which is a subclass of Zend_Db_Select and imposes this restriction. Try this instead:
$db = Zend_Db::factory( ...options... );
$select = new Zend_Db_Select($adapter);
$select->from( 'my_table_name' )->join( ...
If you prefer, the following should be equivalent:
$db = Zend_Db::factory( ...options... );
$db->select()->from( 'my_table_name' )->join( ...