Your SlideShare is downloading. ×
Drupal7  dbtng
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Drupal7 dbtng

3,257
views

Published on

Published in: Technology

0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,257
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Drupal 7: DBTNG
  • 2. DBTNG?Databases:
  • 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. Basic Queries
  • 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. 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. 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. 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. 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. 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. Dynamic Queries
  • 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. 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. 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. 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. 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. 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. Dynamic Queries SELECT queries have both static and dynamic versions INSERT, UPDATE, DELETE, and MERGE queries only support a dynamic version
  • 19. Insert
  • 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. 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. 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. 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. Update
  • 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. 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. Delete
  • 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. Merge
  • 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. 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. 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. 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. 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. Advanced subjects
  • 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. 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. 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. 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. 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. 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. Simplify code Especially for modules creating their own API They need their own query builder Example: Voting API
  • 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. See you in another Galaxy