Drupal 7: DBTNG
DBTNG?Databases:
Databases: The next generation A brand new database layer for drupal7 Support for MySQL, PostgreSQL, SQL Lite Add-on dr...
Basic Queries
Basic Queries Most SELECT queries are simple and  don’t change Drupal calls these: static queries $result = db_query("SE...
Basic Queries Table names  wrapped in curly braces No database-specific syntax in the query. There are no literal valu...
Placeholders Must be unique within a query, and must  begin with a colon. Should never have quotation marks  around them...
Result Object The return value from a db_query() call is a  result object.$list = array();foreach ($result as $record) { ...
Result as array By default, each $record in the result set is  a stdClass object. This is how you get an array:$result =...
Fetch option We can also fetch a single record, or even  just a single field:// Fetch a single record as an object.$recor...
Dynamic Queries
Dynamic Queries To start, we create a new query object with  db_select():$query = db_select(node, n); The first paramete...
Dynamic Queries     We then call additional methods on the      $query object in order to build up the      query logic w...
Dynamic Queries The resulting querySELECT n.nid AS nid, n.title AS title, u.name AS usernameFROM {node} nINNER JOIN {user...
Dynamic Queries Theres one more important method to call  —addTag(). It does mark the type of query it is If a query ha...
Dynamic Queries The node_access tag, is most important  as it allows the node access system to  alter the query, to filte...
Dynamic Queries     Most methods of the select builder return the       select object itself and thus are chainable.    ...
Dynamic Queries SELECT queries have both static and  dynamic versions INSERT, UPDATE, DELETE, and MERGE  queries only su...
Insert
Insert all methods of Insert queries are  chainable.$id = db_insert(imports)     ->fields(array(          name => Groucho...
Insert it supports multi-insert statements$values[] = array(     name => Groucho,     address => 123 Casablanca Ave.,    ...
Insert it supports multi-insert statements$insert = db_insert(imports)     ->fields(array(name, address, phone => 555-121...
Insert On databases that support multi-insert  statements, the preceding code will be run  as a single query. For those t...
Update
Update Update queries look like a hybrid of Insert  and Select statements. consist of both fields to set on a table and ...
Update Return value from execute() for Update  queries = number of records that were  changed. changed does not mean mat...
Delete
Delete Delete queries should come as no  surprise, as they consist of essentially just  a WHERE clause:db_delete(imports)...
Merge
Merge one of the oft-forgotten parts of SQL the most popular open source databases  do not support them directly "If th...
Merge A true merge query is atomic = were  guaranteed that it will run as a single  uninterrupted operation or fail compl...
Mergedb_merge(variable)   ->key(array(name => $name))   ->fields(array(value => serialize($value)))   ->execute(); The ke...
Merge The query can be read as: "If there is a record where the field name  has the value $name, set the value field.  I...
Merge We can also define more complex logic   using the insertFields() and updateFields()   methods.db_merge(people)  ->k...
Advanced subjects
Transactions A transaction in a database is a way to wrap  two or more queries together and declare that  they should be ...
Transactionsfunction my_function() {    $transaction = db_transaction();    try {          $id = db_insert(example)       ...
Slave servers Drupal also supports Master/slave  database replication select queries can be run against a slave  server ...
Slave servers The key of interest = target It specifies which database variant the  system should try. Legal values: de...
Slave servers$result = db_query("SELECT name, filename FROM {system} WHERE type =:type AND status = :status", array(:type ...
Slave servers Data on a slave server is always a little  behind the master server Not all Select queries can handle thei...
Simplify code Especially for modules creating their own  API They need their own query builder Example: Voting API
Drupal 6: 96 code lines                                                                                    Drupal 7: 16 co...
See you in another Galaxy
Upcoming SlideShare
Loading in …5
×

Drupal7 dbtng

3,640 views

Published on

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,640
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Drupal7 dbtng

  1. 1. Drupal 7: DBTNG
  2. 2. DBTNG?Databases:
  3. 3. Databases: The next generation A brand new database layer for drupal7 Support for MySQL, PostgreSQL, SQL Lite Add-on drivers can be made
  4. 4. Basic Queries
  5. 5. Basic Queries Most SELECT queries are simple and don’t change Drupal calls these: static queries $result = db_query("SELECT name, filename FROM {system} WHERE type = :type AND status = :status", array(:type => module, :status => 1));
  6. 6. Basic Queries Table names  wrapped in curly braces No database-specific syntax in the query. There are no literal values in the query. Instead, literal values are specified by placeholders.
  7. 7. Placeholders Must be unique within a query, and must begin with a colon. Should never have quotation marks around them, regardless of the data type. The database server will handle that for us. Should be used for all literal data, even if it will not vary.
  8. 8. Result Object The return value from a db_query() call is a result object.$list = array();foreach ($result as $record) { $list[] = t(@name: @filename, array( @name => $record->name, @filename => $record->filename, ));}
  9. 9. Result as array By default, each $record in the result set is a stdClass object. This is how you get an array:$result = db_query("SELECT name, filename FROM {system} WHERE type =:type AND status = :status", array(:type => module, :status => 1), array(fetch=> PDO::FETCH_ASSOC));
  10. 10. Fetch option We can also fetch a single record, or even just a single field:// Fetch a single record as an object.$record = $result->fetchObject();// Fetch a single record as an array.$record = $result->fetchAssoc();// Fetch just the first field of the next record.$field = $result->fetchField();// Fetch the entire result set at once into an array.$records = $result->fetchAll()
  11. 11. Dynamic Queries
  12. 12. Dynamic Queries To start, we create a new query object with db_select():$query = db_select(node, n); The first parameter is the name of the base table of the query and the second is the alias.
  13. 13. Dynamic Queries  We then call additional methods on the $query object in order to build up the query logic we want to create dynamically$query = db_select(node, n);$query->fields(n, array(nid, title));$u_alias = $query->innerJoin(users ,u, %alias.uid = n.uid);$query->addField($u_alias, name, username);$query->condition("{$u_alias}.name", Bob);$query->condition(n.created, REQUEST_TIME - 604800, >=);$query->orderBy(n.created, DESC);$query->range(0, 5);$query->addTag(node_access);$result = $query->execute();
  14. 14. Dynamic Queries The resulting querySELECT n.nid AS nid, n.title AS title, u.name AS usernameFROM {node} nINNER JOIN {users} u ON u.nid = n.nidWHERE (n.created >= 1286213869) AND (u.name = Bob)ORDER BY n.created DESCLIMIT 5 OFFSET 0
  15. 15. Dynamic Queries Theres one more important method to call —addTag(). It does mark the type of query it is If a query has been tagged then before it is turned into an SQL string it will be passed through hook_query_alter() and hook_query_TAG_alter().
  16. 16. Dynamic Queries The node_access tag, is most important as it allows the node access system to alter the query, to filter out nodes that the current user should not have access to.
  17. 17. Dynamic Queries  Most methods of the select builder return the select object itself and thus are chainable.  The exceptions are the addField() and join() methods, as those need to return a generated alias instead.n);$query = db_select(node,$u_alias = $query->innerJoin(users ,u, %alias.uid = n.uid); $query->addField($u_alias, name, username);$result = $query ->fields(n, array(nid, title)); ->condition("{$u_alias}.name", Bob); ->condition(n.created, REQUEST_TIME - 604800, >=); ->orderBy(n.created, DESC); ->range(0, 5); ->addTag(node_access) ->execute();
  18. 18. Dynamic Queries SELECT queries have both static and dynamic versions INSERT, UPDATE, DELETE, and MERGE queries only support a dynamic version
  19. 19. Insert
  20. 20. Insert all methods of Insert queries are chainable.$id = db_insert(imports) ->fields(array( name => Groucho, address => 123 Casablanca Ave., phone => 555-1212, )) ->execute();
  21. 21. Insert it supports multi-insert statements$values[] = array( name => Groucho, address => 123 Casablanca Ave., phone => 555-1212,);$values[] = array( name => Chico, address => 456 Races St., phone => 555-1234,);$values[] = array( name => Harpo, address => 789 Horn Ave., phone => 555-1234,);$values[] = array( name => Zeppo, address => 22 University Way, phone => 555-3579,);
  22. 22. Insert it supports multi-insert statements$insert = db_insert(imports) ->fields(array(name, address, phone => 555-1212));foreach ($values as $value) { $insert->values($value);}$insert->execute();
  23. 23. Insert On databases that support multi-insert statements, the preceding code will be run as a single query. For those that dont, they will run as separate queries within a single transaction. Note that in a multi-insert query the return value from execute() is undefined and should be ignored.
  24. 24. Update
  25. 25. Update Update queries look like a hybrid of Insert and Select statements. consist of both fields to set on a table and conditions to restrict the query.db_update(imports) ->condition(name, Chico) ->fields(array(address => Go West St.)) ->execute(); Resulting query:UPDATE {imports} SET address = Go West St. WHERE name = Chico;
  26. 26. Update Return value from execute() for Update queries = number of records that were changed. changed does not mean matched. If the WHERE portion of the query matches a record but if that record already has the values that it would be set to, it will not be changed and would not count towards the return value from execute().
  27. 27. Delete
  28. 28. Delete Delete queries should come as no surprise, as they consist of essentially just a WHERE clause:db_delete(imports) ->condition(name => Zeppo) ->execute(); Return value from execute() = number of records that were deleted by the query.
  29. 29. Merge
  30. 30. Merge one of the oft-forgotten parts of SQL the most popular open source databases do not support them directly "If this record exists, update it with this query otherwise create it with this other query" It is most useful for setting records that may or may not exist yet, that is, merging data into the table.
  31. 31. Merge A true merge query is atomic = were guaranteed that it will run as a single uninterrupted operation or fail completely. Since most of the databases Drupal works with do not directly support Merge queries, Drupal emulates them with multiple queries and a transaction, which in most cases is close enough.
  32. 32. Mergedb_merge(variable) ->key(array(name => $name)) ->fields(array(value => serialize($value))) ->execute(); The key() method takes an associative array of field/value pairs that are the pivot of the query. The fields() method is about the fields to set
  33. 33. Merge The query can be read as: "If there is a record where the field name has the value $name, set the value field. If not, insert a new record with name equal to $name and value equal to the given string.”
  34. 34. Merge We can also define more complex logic using the insertFields() and updateFields() methods.db_merge(people) ->key(array(job => Speaker)) ->insertFields(array( age => 31, name => Meredith, )) ->updateFields(array( name => Tiffany, )) ->execute();
  35. 35. Advanced subjects
  36. 36. Transactions A transaction in a database is a way to wrap two or more queries together and declare that they should be atomic. That is, either all succeed or none succeed. We start a transaction by creating a transaction object. Everything we do to the database is then part of the transaction until that object is destroyed, at which point the entire query is committed at once. In most cases, we let PHP destroy the transaction object for us when a function ends.
  37. 37. Transactionsfunction my_function() { $transaction = db_transaction(); try { $id = db_insert(example) ->fields(array( field1 => mystring, field2 => 5, )) ->execute(); my_other_function($id); return $id; } catch (Exception $e) { $transaction->rollback(); watchdog_exception(type, $e); }}
  38. 38. Slave servers Drupal also supports Master/slave database replication select queries can be run against a slave server to offload the work to separate servers The third parameter to db_query() or db_select() is an array of options that tweak the behavior of the query.
  39. 39. Slave servers The key of interest = target It specifies which database variant the system should try. Legal values: default (which is the default) and slave. If "slave" is specified, Drupal will try to run the query against a slave server. If one is not available, it will silently fall back to the default server.
  40. 40. Slave servers$result = db_query("SELECT name, filename FROM {system} WHERE type =:type AND status = :status", array(:type => module, :status => 1), array(fetch=> PDO::FETCH_ASSOC, target => slave));
  41. 41. Slave servers Data on a slave server is always a little behind the master server Not all Select queries can handle their data being slightly stale After writing data, we can call db_ignore_slave(). It will make a note in the active session to disable the slave server for the current user only for a configurable period of time. (The default is five minutes.)
  42. 42. Simplify code Especially for modules creating their own API They need their own query builder Example: Voting API
  43. 43. Drupal 6: 96 code lines Drupal 7: 16 code lines<?php/*** Select individual votes from the database. <?php*/function votingapi_select_votes($criteria = array(), $limit = 0) { function votingapi_select_votes($criteria = array(), $limit = 0) { $anon_window = variable_get(votingapi_anonymous_window, 3600); if (!empty($criteria[vote_source]) && $anon_window > 0) { $criteria[timestamp] = time() - $anon_window; $anon_window = variable_get(votingapi_anonymous_window, 3600); } $votes = array(); if (!empty($criteria[vote_source]) && $anon_window >= 0) { $result = _votingapi_select(vote, $criteria, $limit); while ($vote = db_fetch_array($result)) { $votes[] = $vote; $criteria[timestamp] = REQUEST_TIME - $anon_window; } return $votes; }}/** $query = db_select(votingapi_vote)->fields(votingapi_vote);* Internal helper function constructs WHERE clauses. Dont use unless youre me.*/ foreach ($criteria as $key => $value) {function _votingapi_query($table = vote, $criteria = array(), $alias = v.) { $criteria += array( vote_id => NULL, $query->condition($key, $value, is_array($value) ? IN : =); vote_cache_id => NULL, content_id => NULL, } content_type => NULL, value_type => NULL, value => NULL, if (!empty($limit)) { tag => NULL, uid => NULL, $query->range(0, $limit); timestamp => NULL, vote_source => NULL, function => NULL, } ); return $query->execute()->fetchAll(PDO::FETCH_ASSOC); $query = ; $args = array(); if (!empty($criteria[vote_id])) { } } _votingapi_query_builder($alias . vote_id, $criteria[vote_id], $query, $args); ?> elseif (!empty($criteria[vote_cache_id])) { _votingapi_query_builder($alias . vote_cache_id, $criteria[vote_cache_id], $query, $args); } else { _votingapi_query_builder($alias . content_type, $criteria[content_type], $query, $args, TRUE); _votingapi_query_builder($alias . content_id, $criteria[content_id], $query, $args); _votingapi_query_builder($alias . value_type, $criteria[value_type], $query, $args, TRUE); _votingapi_query_builder($alias . tag, $criteria[tag], $query, $args, TRUE); _votingapi_query_builder($alias . function, $criteria[function], $query, $args, TRUE); _votingapi_query_builder($alias . uid, $criteria[uid], $query, $args); _votingapi_query_builder($alias . vote_source, $criteria[vote_source], $query, $args, TRUE); _votingapi_query_builder($alias . timestamp, $criteria[timestamp], $query, $args); } return array(query => $query, args => $args);}/*** Internal helper function constructs individual elements of WHERE clauses.* Dont use unless youre me.*/function _votingapi_query_builder($name, $value, &$query, &$args, $col_is_string = FALSE) { if (!isset($value)) { // Do nothing } elseif ($name === timestamp) { $query .= " AND timestamp >= %d"; $args[] = $value; } elseif ($name === v.timestamp) { $query .= " AND v.timestamp >= %d"; $args[] = $value; } else { if (is_array($value)) { if ($col_is_string) { $query .= " AND $name IN (" . db_placeholders($value, varchar) . ")"; $args = array_merge($args, $value); } else { $query .= " AND $name IN (" . db_placeholders($value, int) . ")"; $args = array_merge($args, $value); } } else { if ($col_is_string) { $query .= " AND $name = %s"; $args[] = $value; } else { $query .= " AND $name = %d"; $args[] = $value; } } }}?>
  44. 44. See you in another Galaxy

×