| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242 | <?php/** * Dummy class for fetching into a class. * * PDO supports using a new instance of an arbitrary class for records * rather than just a stdClass or array. This class is for testing that * functionality. (See testQueryFetchClass() below) */class FakeRecord { }/** * Base test class for databases. * * Because all database tests share the same test data, we can centralize that * here. */class DatabaseTestCase extends DrupalWebTestCase {  protected $profile = 'testing';  function setUp() {    parent::setUp('database_test');    $schema['test'] = drupal_get_schema('test');    $schema['test_people'] = drupal_get_schema('test_people');    $schema['test_people_copy'] = drupal_get_schema('test_people_copy');    $schema['test_one_blob'] = drupal_get_schema('test_one_blob');    $schema['test_two_blobs'] = drupal_get_schema('test_two_blobs');    $schema['test_task'] = drupal_get_schema('test_task');    $this->installTables($schema);    $this->addSampleData();  }  /**   * Set up several tables needed by a certain test.   *   * @param $schema   *   An array of table definitions to install.   */  function installTables($schema) {    // This ends up being a test for table drop and create, too, which is nice.    foreach ($schema as $name => $data) {      if (db_table_exists($name)) {        db_drop_table($name);      }      db_create_table($name, $data);    }    foreach ($schema as $name => $data) {      $this->assertTrue(db_table_exists($name), format_string('Table @name created successfully.', array('@name' => $name)));    }  }  /**   * Set up tables for NULL handling.   */  function ensureSampleDataNull() {    $schema['test_null'] = drupal_get_schema('test_null');    $this->installTables($schema);    db_insert('test_null')    ->fields(array('name', 'age'))    ->values(array(      'name' => 'Kermit',      'age' => 25,    ))    ->values(array(      'name' => 'Fozzie',      'age' => NULL,    ))    ->values(array(      'name' => 'Gonzo',      'age' => 27,    ))    ->execute();  }  /**   * Setup our sample data.   *   * These are added using db_query(), since we're not trying to test the   * INSERT operations here, just populate.   */  function addSampleData() {    // We need the IDs, so we can't use a multi-insert here.    $john = db_insert('test')      ->fields(array(        'name' => 'John',        'age' => 25,        'job' => 'Singer',      ))      ->execute();    $george = db_insert('test')      ->fields(array(        'name' => 'George',        'age' => 27,        'job' => 'Singer',      ))      ->execute();    $ringo = db_insert('test')      ->fields(array(        'name' => 'Ringo',        'age' => 28,        'job' => 'Drummer',      ))      ->execute();    $paul = db_insert('test')      ->fields(array(        'name' => 'Paul',        'age' => 26,        'job' => 'Songwriter',      ))      ->execute();    db_insert('test_people')      ->fields(array(        'name' => 'Meredith',        'age' => 30,        'job' => 'Speaker',      ))      ->execute();    db_insert('test_task')      ->fields(array('pid', 'task', 'priority'))      ->values(array(        'pid' => $john,        'task' => 'eat',        'priority' => 3,      ))      ->values(array(        'pid' => $john,        'task' => 'sleep',        'priority' => 4,      ))      ->values(array(        'pid' => $john,        'task' => 'code',        'priority' => 1,      ))      ->values(array(        'pid' => $george,        'task' => 'sing',        'priority' => 2,      ))      ->values(array(        'pid' => $george,        'task' => 'sleep',        'priority' => 2,      ))      ->values(array(        'pid' => $paul,        'task' => 'found new band',        'priority' => 1,      ))      ->values(array(        'pid' => $paul,        'task' => 'perform at superbowl',        'priority' => 3,      ))      ->execute();  }}/** * Test connection management. */class DatabaseConnectionTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Connection tests',      'description' => 'Tests of the core database system.',      'group' => 'Database',    );  }  /**   * Test that connections return appropriate connection objects.   */  function testConnectionRouting() {    // Clone the master credentials to a slave connection.    // Note this will result in two independent connection objects that happen    // to point to the same place.    $connection_info = Database::getConnectionInfo('default');    Database::addConnectionInfo('default', 'slave', $connection_info['default']);    $db1 = Database::getConnection('default', 'default');    $db2 = Database::getConnection('slave', 'default');    $this->assertNotNull($db1, 'default connection is a real connection object.');    $this->assertNotNull($db2, 'slave connection is a real connection object.');    $this->assertNotIdentical($db1, $db2, 'Each target refers to a different connection.');    // Try to open those targets another time, that should return the same objects.    $db1b = Database::getConnection('default', 'default');    $db2b = Database::getConnection('slave', 'default');    $this->assertIdentical($db1, $db1b, 'A second call to getConnection() returns the same object.');    $this->assertIdentical($db2, $db2b, 'A second call to getConnection() returns the same object.');    // Try to open an unknown target.    $unknown_target = $this->randomName();    $db3 = Database::getConnection($unknown_target, 'default');    $this->assertNotNull($db3, 'Opening an unknown target returns a real connection object.');    $this->assertIdentical($db1, $db3, 'An unknown target opens the default connection.');    // Try to open that unknown target another time, that should return the same object.    $db3b = Database::getConnection($unknown_target, 'default');    $this->assertIdentical($db3, $db3b, 'A second call to getConnection() returns the same object.');  }  /**   * Test that connections return appropriate connection objects.   */  function testConnectionRoutingOverride() {    // Clone the master credentials to a slave connection.    // Note this will result in two independent connection objects that happen    // to point to the same place.    $connection_info = Database::getConnectionInfo('default');    Database::addConnectionInfo('default', 'slave', $connection_info['default']);    Database::ignoreTarget('default', 'slave');    $db1 = Database::getConnection('default', 'default');    $db2 = Database::getConnection('slave', 'default');    $this->assertIdentical($db1, $db2, 'Both targets refer to the same connection.');  }  /**   * Tests the closing of a database connection.   */  function testConnectionClosing() {    // Open the default target so we have an object to compare.    $db1 = Database::getConnection('default', 'default');    // Try to close the default connection, then open a new one.    Database::closeConnection('default', 'default');    $db2 = Database::getConnection('default', 'default');    // Opening a connection after closing it should yield an object different than the original.    $this->assertNotIdentical($db1, $db2, 'Opening the default connection after it is closed returns a new object.');  }  /**   * Tests the connection options of the active database.   */  function testConnectionOptions() {    $connection_info = Database::getConnectionInfo('default');    // Be sure we're connected to the default database.    $db = Database::getConnection('default', 'default');    $connectionOptions = $db->getConnectionOptions();    // In the MySQL driver, the port can be different, so check individual    // options.    $this->assertEqual($connection_info['default']['driver'], $connectionOptions['driver'], 'The default connection info driver matches the current connection options driver.');    $this->assertEqual($connection_info['default']['database'], $connectionOptions['database'], 'The default connection info database matches the current connection options database.');    // Set up identical slave and confirm connection options are identical.    Database::addConnectionInfo('default', 'slave', $connection_info['default']);    $db2 = Database::getConnection('slave', 'default');    $connectionOptions2 = $db2->getConnectionOptions();    // Get a fresh copy of the default connection options.    $connectionOptions = $db->getConnectionOptions();    $this->assertIdentical($connectionOptions, $connectionOptions2, 'The default and slave connection options are identical.');    // Set up a new connection with different connection info.    $test = $connection_info['default'];    $test['database'] .= 'test';    Database::addConnectionInfo('test', 'default', $test);    $connection_info = Database::getConnectionInfo('test');    // Get a fresh copy of the default connection options.    $connectionOptions = $db->getConnectionOptions();    $this->assertNotEqual($connection_info['default']['database'], $connectionOptions['database'], 'The test connection info database does not match the current connection options database.');  }}/** * Test cloning Select queries. */class DatabaseSelectCloneTest extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Select tests, cloning',      'description' => 'Test cloning Select queries.',      'group' => 'Database',    );  }  /**   * Test that subqueries as value within conditions are cloned properly.   */  function testSelectConditionSubQueryCloning() {    $subquery = db_select('test', 't');    $subquery->addField('t', 'id', 'id');    $subquery->condition('age', 28, '<');    $query = db_select('test', 't');    $query->addField('t', 'name', 'name');    $query->condition('id', $subquery, 'IN');    $clone = clone $query;    // Cloned query should not be altered by the following modification    // happening on original query.    $subquery->condition('age', 25, '>');    $clone_result = $clone->countQuery()->execute()->fetchField();    $query_result = $query->countQuery()->execute()->fetchField();    // Make sure the cloned query has not been modified    $this->assertEqual(3, $clone_result, 'The cloned query returns the expected number of rows');    $this->assertEqual(2, $query_result, 'The query returns the expected number of rows');  }}/** * Test fetch actions, part 1. * * We get timeout errors if we try to run too many tests at once. */class DatabaseFetchTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Fetch tests',      'description' => 'Test the Database system\'s various fetch capabilities.',      'group' => 'Database',    );  }  /**   * Confirm that we can fetch a record properly in default object mode.   */  function testQueryFetchDefault() {    $records = array();    $result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25));    $this->assertTrue($result instanceof DatabaseStatementInterface, 'Result set is a Drupal statement object.');    foreach ($result as $record) {      $records[] = $record;      $this->assertTrue(is_object($record), 'Record is an object.');      $this->assertIdentical($record->name, 'John', '25 year old is John.');    }    $this->assertIdentical(count($records), 1, 'There is only one record.');  }  /**   * Confirm that we can fetch a record to an object explicitly.   */  function testQueryFetchObject() {    $records = array();    $result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_OBJ));    foreach ($result as $record) {      $records[] = $record;      $this->assertTrue(is_object($record), 'Record is an object.');      $this->assertIdentical($record->name, 'John', '25 year old is John.');    }    $this->assertIdentical(count($records), 1, 'There is only one record.');  }  /**   * Confirm that we can fetch a record to an array associative explicitly.   */  function testQueryFetchArray() {    $records = array();    $result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_ASSOC));    foreach ($result as $record) {      $records[] = $record;      if ($this->assertTrue(is_array($record), 'Record is an array.')) {        $this->assertIdentical($record['name'], 'John', 'Record can be accessed associatively.');      }    }    $this->assertIdentical(count($records), 1, 'There is only one record.');  }  /**   * Confirm that we can fetch a record into a new instance of a custom class.   *   * @see FakeRecord   */  function testQueryFetchClass() {    $records = array();    $result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => 'FakeRecord'));    foreach ($result as $record) {      $records[] = $record;      if ($this->assertTrue($record instanceof FakeRecord, 'Record is an object of class FakeRecord.')) {        $this->assertIdentical($record->name, 'John', '25 year old is John.');      }    }    $this->assertIdentical(count($records), 1, 'There is only one record.');  }}/** * Test fetch actions, part 2. * * We get timeout errors if we try to run too many tests at once. */class DatabaseFetch2TestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Fetch tests, part 2',      'description' => 'Test the Database system\'s various fetch capabilities.',      'group' => 'Database',    );  }  function setUp() {    parent::setUp();  }  // Confirm that we can fetch a record into an indexed array explicitly.  function testQueryFetchNum() {    $records = array();    $result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_NUM));    foreach ($result as $record) {      $records[] = $record;      if ($this->assertTrue(is_array($record), 'Record is an array.')) {        $this->assertIdentical($record[0], 'John', 'Record can be accessed numerically.');      }    }    $this->assertIdentical(count($records), 1, 'There is only one record');  }  /**   * Confirm that we can fetch a record into a doubly-keyed array explicitly.   */  function testQueryFetchBoth() {    $records = array();    $result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_BOTH));    foreach ($result as $record) {      $records[] = $record;      if ($this->assertTrue(is_array($record), 'Record is an array.')) {        $this->assertIdentical($record[0], 'John', 'Record can be accessed numerically.');        $this->assertIdentical($record['name'], 'John', 'Record can be accessed associatively.');      }    }    $this->assertIdentical(count($records), 1, 'There is only one record.');  }  /**   * Confirm that we can fetch an entire column of a result set at once.   */  function testQueryFetchCol() {    $records = array();    $result = db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25));    $column = $result->fetchCol();    $this->assertIdentical(count($column), 3, 'fetchCol() returns the right number of records.');    $result = db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25));    $i = 0;    foreach ($result as $record) {      $this->assertIdentical($record->name, $column[$i++], 'Column matches direct accesss.');    }  }}/** * Test the insert builder. */class DatabaseInsertTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Insert tests',      'description' => 'Test the Insert query builder.',      'group' => 'Database',    );  }  /**   * Test the very basic insert functionality.   */  function testSimpleInsert() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $query = db_insert('test');    $query->fields(array(      'name' => 'Yoko',      'age' => '29',    ));    $query->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $this->assertIdentical($num_records_before + 1, (int) $num_records_after, 'Record inserts correctly.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Yoko'))->fetchField();    $this->assertIdentical($saved_age, '29', 'Can retrieve after inserting.');  }  /**   * Test that we can insert multiple records in one query object.   */  function testMultiInsert() {    $num_records_before = (int) db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $query = db_insert('test');    $query->fields(array(      'name' => 'Larry',      'age' => '30',    ));    // We should be able to specify values in any order if named.    $query->values(array(      'age' => '31',      'name' => 'Curly',    ));    // We should be able to say "use the field order".    // This is not the recommended mechanism for most cases, but it should work.    $query->values(array('Moe', '32'));    $query->execute();    $num_records_after = (int) db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $this->assertIdentical($num_records_before + 3, $num_records_after, 'Record inserts correctly.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Larry'))->fetchField();    $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Curly'))->fetchField();    $this->assertIdentical($saved_age, '31', 'Can retrieve after inserting.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Moe'))->fetchField();    $this->assertIdentical($saved_age, '32', 'Can retrieve after inserting.');  }  /**   * Test that an insert object can be reused with new data after it executes.   */  function testRepeatedInsert() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $query = db_insert('test');    $query->fields(array(      'name' => 'Larry',      'age' => '30',    ));    $query->execute();  // This should run the insert, but leave the fields intact.    // We should be able to specify values in any order if named.    $query->values(array(      'age' => '31',      'name' => 'Curly',    ));    $query->execute();    // We should be able to say "use the field order".    $query->values(array('Moe', '32'));    $query->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $this->assertIdentical((int) $num_records_before + 3, (int) $num_records_after, 'Record inserts correctly.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Larry'))->fetchField();    $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Curly'))->fetchField();    $this->assertIdentical($saved_age, '31', 'Can retrieve after inserting.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Moe'))->fetchField();    $this->assertIdentical($saved_age, '32', 'Can retrieve after inserting.');  }  /**   * Test that we can specify fields without values and specify values later.   */  function testInsertFieldOnlyDefinintion() {    // This is useful for importers, when we want to create a query and define    // its fields once, then loop over a multi-insert execution.    db_insert('test')      ->fields(array('name', 'age'))      ->values(array('Larry', '30'))      ->values(array('Curly', '31'))      ->values(array('Moe', '32'))      ->execute();    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Larry'))->fetchField();    $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Curly'))->fetchField();    $this->assertIdentical($saved_age, '31', 'Can retrieve after inserting.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Moe'))->fetchField();    $this->assertIdentical($saved_age, '32', 'Can retrieve after inserting.');  }  /**   * Test that inserts return the proper auto-increment ID.   */  function testInsertLastInsertID() {    $id = db_insert('test')      ->fields(array(        'name' => 'Larry',        'age' => '30',      ))      ->execute();    $this->assertIdentical($id, '5', 'Auto-increment ID returned successfully.');  }  /**   * Test that the INSERT INTO ... SELECT (fields) ... syntax works.   */  function testInsertSelectFields() {    $query = db_select('test_people', 'tp');    // The query builder will always append expressions after fields.    // Add the expression first to test that the insert fields are correctly    // re-ordered.    $query->addExpression('tp.age', 'age');    $query      ->fields('tp', array('name','job'))      ->condition('tp.name', 'Meredith');    // The resulting query should be equivalent to:    // INSERT INTO test (age, name, job)    // SELECT tp.age AS age, tp.name AS name, tp.job AS job    // FROM test_people tp    // WHERE tp.name = 'Meredith'    db_insert('test')      ->from($query)      ->execute();    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Meredith'))->fetchField();    $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');  }  /**   * Tests that the INSERT INTO ... SELECT * ... syntax works.   */  function testInsertSelectAll() {    $query = db_select('test_people', 'tp')      ->fields('tp')      ->condition('tp.name', 'Meredith');    // The resulting query should be equivalent to:    // INSERT INTO test_people_copy    // SELECT *    // FROM test_people tp    // WHERE tp.name = 'Meredith'    db_insert('test_people_copy')      ->from($query)      ->execute();    $saved_age = db_query('SELECT age FROM {test_people_copy} WHERE name = :name', array(':name' => 'Meredith'))->fetchField();    $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');  }}/** * Insert tests using LOB fields, which are weird on some databases. */class DatabaseInsertLOBTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Insert tests, LOB fields',      'description' => 'Test the Insert query builder with LOB fields.',      'group' => 'Database',    );  }  /**   * Test that we can insert a single blob field successfully.   */  function testInsertOneBlob() {    $data = "This is\000a test.";    $this->assertTrue(strlen($data) === 15, 'Test data contains a NULL.');    $id = db_insert('test_one_blob')      ->fields(array('blob1' => $data))      ->execute();    $r = db_query('SELECT * FROM {test_one_blob} WHERE id = :id', array(':id' => $id))->fetchAssoc();    $this->assertTrue($r['blob1'] === $data, format_string('Can insert a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r))));  }  /**   * Test that we can insert multiple blob fields in the same query.   */  function testInsertMultipleBlob() {    $id = db_insert('test_two_blobs')      ->fields(array(        'blob1' => 'This is',        'blob2' => 'a test',      ))      ->execute();    $r = db_query('SELECT * FROM {test_two_blobs} WHERE id = :id', array(':id' => $id))->fetchAssoc();    $this->assertTrue($r['blob1'] === 'This is' && $r['blob2'] === 'a test', 'Can insert multiple blobs per row.');  }}/** * Insert tests for "database default" values. */class DatabaseInsertDefaultsTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Insert tests, default fields',      'description' => 'Test the Insert query builder with default values.',      'group' => 'Database',    );  }  /**   * Test that we can run a query that is "default values for everything".   */  function testDefaultInsert() {    $query = db_insert('test')->useDefaults(array('job'));    $id = $query->execute();    $schema = drupal_get_schema('test');    $job = db_query('SELECT job FROM {test} WHERE id = :id', array(':id' => $id))->fetchField();    $this->assertEqual($job, $schema['fields']['job']['default'], 'Default field value is set.');  }  /**   * Test that no action will be preformed if no fields are specified.   */  function testDefaultEmptyInsert() {    $num_records_before = (int) db_query('SELECT COUNT(*) FROM {test}')->fetchField();    try {      $result = db_insert('test')->execute();      // This is only executed if no exception has been thrown.      $this->fail('Expected exception NoFieldsException has not been thrown.');    } catch (NoFieldsException $e) {      $this->pass('Expected exception NoFieldsException has been thrown.');    }    $num_records_after = (int) db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $this->assertIdentical($num_records_before, $num_records_after, 'Do nothing as no fields are specified.');  }  /**   * Test that we can insert fields with values and defaults in the same query.   */  function testDefaultInsertWithFields() {    $query = db_insert('test')      ->fields(array('name' => 'Bob'))      ->useDefaults(array('job'));    $id = $query->execute();    $schema = drupal_get_schema('test');    $job = db_query('SELECT job FROM {test} WHERE id = :id', array(':id' => $id))->fetchField();    $this->assertEqual($job, $schema['fields']['job']['default'], 'Default field value is set.');  }}/** * Update builder tests. */class DatabaseUpdateTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Update tests',      'description' => 'Test the Update query builder.',      'group' => 'Database',    );  }  /**   * Confirm that we can update a single record successfully.   */  function testSimpleUpdate() {    $num_updated = db_update('test')      ->fields(array('name' => 'Tiffany'))      ->condition('id', 1)      ->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $saved_name = db_query('SELECT name FROM {test} WHERE id = :id', array(':id' => 1))->fetchField();    $this->assertIdentical($saved_name, 'Tiffany', 'Updated name successfully.');  }  /**   * Confirm updating to NULL.   */  function testSimpleNullUpdate() {    $this->ensureSampleDataNull();    $num_updated = db_update('test_null')      ->fields(array('age' => NULL))      ->condition('name', 'Kermit')      ->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $saved_age = db_query('SELECT age FROM {test_null} WHERE name = :name', array(':name' => 'Kermit'))->fetchField();    $this->assertNull($saved_age, 'Updated name successfully.');  }  /**   * Confirm that we can update a multiple records successfully.   */  function testMultiUpdate() {    $num_updated = db_update('test')      ->fields(array('job' => 'Musician'))      ->condition('job', 'Singer')      ->execute();    $this->assertIdentical($num_updated, 2, 'Updated 2 records.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');  }  /**   * Confirm that we can update a multiple records with a non-equality condition.   */  function testMultiGTUpdate() {    $num_updated = db_update('test')      ->fields(array('job' => 'Musician'))      ->condition('age', 26, '>')      ->execute();    $this->assertIdentical($num_updated, 2, 'Updated 2 records.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');  }  /**   * Confirm that we can update a multiple records with a where call.   */  function testWhereUpdate() {    $num_updated = db_update('test')      ->fields(array('job' => 'Musician'))      ->where('age > :age', array(':age' => 26))      ->execute();    $this->assertIdentical($num_updated, 2, 'Updated 2 records.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');  }  /**   * Confirm that we can stack condition and where calls.   */  function testWhereAndConditionUpdate() {    $update = db_update('test')      ->fields(array('job' => 'Musician'))      ->where('age > :age', array(':age' => 26))      ->condition('name', 'Ringo');    $num_updated = $update->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');  }  /**   * Test updating with expressions.   */  function testExpressionUpdate() {    // Set age = 1 for a single row for this test to work.    db_update('test')      ->condition('id', 1)      ->fields(array('age' => 1))      ->execute();    // Ensure that expressions are handled properly.  This should set every    // record's age to a square of itself, which will change only three of the    // four records in the table since 1*1 = 1. That means only three records    // are modified, so we should get back 3, not 4, from execute().    $num_rows = db_update('test')      ->expression('age', 'age * age')      ->execute();    $this->assertIdentical($num_rows, 3, 'Number of affected rows are returned.');  }  /**   * Confirm that we can update the primary key of a record successfully.   */  function testPrimaryKeyUpdate() {    $num_updated = db_update('test')      ->fields(array('id' => 42, 'name' => 'John'))      ->condition('id', 1)      ->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $saved_name= db_query('SELECT name FROM {test} WHERE id = :id', array(':id' => 42))->fetchField();    $this->assertIdentical($saved_name, 'John', 'Updated primary key successfully.');  }}/** * Tests for more complex update statements. */class DatabaseUpdateComplexTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Update tests, Complex',      'description' => 'Test the Update query builder, complex queries.',      'group' => 'Database',    );  }  /**   * Test updates with OR conditionals.   */  function testOrConditionUpdate() {    $update = db_update('test')      ->fields(array('job' => 'Musician'))      ->condition(db_or()        ->condition('name', 'John')        ->condition('name', 'Paul')      );    $num_updated = $update->execute();    $this->assertIdentical($num_updated, 2, 'Updated 2 records.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');  }  /**   * Test WHERE IN clauses.   */  function testInConditionUpdate() {    $num_updated = db_update('test')      ->fields(array('job' => 'Musician'))      ->condition('name', array('John', 'Paul'), 'IN')      ->execute();    $this->assertIdentical($num_updated, 2, 'Updated 2 records.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');  }  /**   * Test WHERE NOT IN clauses.   */  function testNotInConditionUpdate() {    // The o is lowercase in the 'NoT IN' operator, to make sure the operators    // work in mixed case.    $num_updated = db_update('test')      ->fields(array('job' => 'Musician'))      ->condition('name', array('John', 'Paul', 'George'), 'NoT IN')      ->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');  }  /**   * Test BETWEEN conditional clauses.   */  function testBetweenConditionUpdate() {    $num_updated = db_update('test')      ->fields(array('job' => 'Musician'))      ->condition('age', array(25, 26), 'BETWEEN')      ->execute();    $this->assertIdentical($num_updated, 2, 'Updated 2 records.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');  }  /**   * Test LIKE conditionals.   */  function testLikeConditionUpdate() {    $num_updated = db_update('test')      ->fields(array('job' => 'Musician'))      ->condition('name', '%ge%', 'LIKE')      ->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');  }  /**   * Test update with expression values.   */  function testUpdateExpression() {    $before_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetchField();    $GLOBALS['larry_test'] = 1;    $num_updated = db_update('test')      ->condition('name', 'Ringo')      ->fields(array('job' => 'Musician'))      ->expression('age', 'age + :age', array(':age' => 4))      ->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();    $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');    $person = db_query('SELECT * FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetch();    $this->assertEqual($person->name, 'Ringo', 'Name set correctly.');    $this->assertEqual($person->age, $before_age + 4, 'Age set correctly.');    $this->assertEqual($person->job, 'Musician', 'Job set correctly.');    $GLOBALS['larry_test'] = 0;  }  /**   * Test update with only expression values.   */  function testUpdateOnlyExpression() {    $before_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetchField();    $num_updated = db_update('test')      ->condition('name', 'Ringo')      ->expression('age', 'age + :age', array(':age' => 4))      ->execute();    $this->assertIdentical($num_updated, 1, 'Updated 1 record.');    $after_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetchField();    $this->assertEqual($before_age + 4, $after_age, 'Age updated correctly');  }}/** * Test update queries involving LOB values. */class DatabaseUpdateLOBTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Update tests, LOB',      'description' => 'Test the Update query builder with LOB fields.',      'group' => 'Database',    );  }  /**   * Confirm that we can update a blob column.   */  function testUpdateOneBlob() {    $data = "This is\000a test.";    $this->assertTrue(strlen($data) === 15, 'Test data contains a NULL.');    $id = db_insert('test_one_blob')      ->fields(array('blob1' => $data))      ->execute();    $data .= $data;    db_update('test_one_blob')      ->condition('id', $id)      ->fields(array('blob1' => $data))      ->execute();    $r = db_query('SELECT * FROM {test_one_blob} WHERE id = :id', array(':id' => $id))->fetchAssoc();    $this->assertTrue($r['blob1'] === $data, format_string('Can update a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r))));  }  /**   * Confirm that we can update two blob columns in the same table.   */  function testUpdateMultipleBlob() {    $id = db_insert('test_two_blobs')      ->fields(array(        'blob1' => 'This is',        'blob2' => 'a test',      ))      ->execute();    db_update('test_two_blobs')      ->condition('id', $id)      ->fields(array('blob1' => 'and so', 'blob2' => 'is this'))      ->execute();    $r = db_query('SELECT * FROM {test_two_blobs} WHERE id = :id', array(':id' => $id))->fetchAssoc();    $this->assertTrue($r['blob1'] === 'and so' && $r['blob2'] === 'is this', 'Can update multiple blobs per row.');  }}/** * Delete/Truncate tests. * * The DELETE tests are not as extensive, as all of the interesting code for * DELETE queries is in the conditional which is identical to the UPDATE and * SELECT conditional handling. * * The TRUNCATE tests are not extensive either, because the behavior of * TRUNCATE queries is not consistent across database engines. We only test * that a TRUNCATE query actually deletes all rows from the target table. */class DatabaseDeleteTruncateTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Delete/Truncate tests',      'description' => 'Test the Delete and Truncate query builders.',      'group' => 'Database',    );  }  /**   * Confirm that we can use a subselect in a delete successfully.   */  function testSubselectDelete() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_task}')->fetchField();    $pid_to_delete = db_query("SELECT * FROM {test_task} WHERE task = 'sleep'")->fetchField();    $subquery = db_select('test', 't')      ->fields('t', array('id'))      ->condition('t.id', array($pid_to_delete), 'IN');    $delete = db_delete('test_task')      ->condition('task', 'sleep')      ->condition('pid', $subquery, 'IN');    $num_deleted = $delete->execute();    $this->assertEqual($num_deleted, 1, "Deleted 1 record.");    $num_records_after = db_query('SELECT COUNT(*) FROM {test_task}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after + $num_deleted, 'Deletion adds up.');  }  /**   * Confirm that we can delete a single record successfully.   */  function testSimpleDelete() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $num_deleted = db_delete('test')      ->condition('id', 1)      ->execute();    $this->assertIdentical($num_deleted, 1, 'Deleted 1 record.');    $num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after + $num_deleted, 'Deletion adds up.');  }  /**   * Confirm that we can truncate a whole table successfully.   */  function testTruncate() {    $num_records_before = db_query("SELECT COUNT(*) FROM {test}")->fetchField();    db_truncate('test')->execute();    $num_records_after = db_query("SELECT COUNT(*) FROM {test}")->fetchField();    $this->assertEqual(0, $num_records_after, 'Truncate really deletes everything.');  }}/** * Test the MERGE query builder. */class DatabaseMergeTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Merge tests',      'description' => 'Test the Merge query builder.',      'group' => 'Database',    );  }  /**   * Confirm that we can merge-insert a record successfully.   */  function testMergeInsert() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $result = db_merge('test_people')      ->key(array('job' => 'Presenter'))      ->fields(array(        'age' => 31,        'name' => 'Tiffany',      ))      ->execute();    $this->assertEqual($result, MergeQuery::STATUS_INSERT, 'Insert status returned.');    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before + 1, $num_records_after, 'Merge inserted properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Presenter'))->fetch();    $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');    $this->assertEqual($person->age, 31, 'Age set correctly.');    $this->assertEqual($person->job, 'Presenter', 'Job set correctly.');  }  /**   * Confirm that we can merge-update a record successfully.   */  function testMergeUpdate() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $result = db_merge('test_people')      ->key(array('job' => 'Speaker'))      ->fields(array(        'age' => 31,        'name' => 'Tiffany',      ))      ->execute();    $this->assertEqual($result, MergeQuery::STATUS_UPDATE, 'Update status returned.');    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();    $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');    $this->assertEqual($person->age, 31, 'Age set correctly.');    $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');  }  /**   * Confirm that we can merge-update a record successfully, with different insert and update.   */  function testMergeUpdateExcept() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    db_merge('test_people')      ->key(array('job' => 'Speaker'))      ->insertFields(array('age' => 31))      ->updateFields(array('name' => 'Tiffany'))      ->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();    $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');    $this->assertEqual($person->age, 30, 'Age skipped correctly.');    $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');  }  /**   * Confirm that we can merge-update a record successfully, with alternate replacement.   */  function testMergeUpdateExplicit() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    db_merge('test_people')      ->key(array('job' => 'Speaker'))      ->insertFields(array(        'age' => 31,        'name' => 'Tiffany',      ))      ->updateFields(array(        'name' => 'Joe',      ))      ->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();    $this->assertEqual($person->name, 'Joe', 'Name set correctly.');    $this->assertEqual($person->age, 30, 'Age skipped correctly.');    $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');  }  /**   * Confirm that we can merge-update a record successfully, with expressions.   */  function testMergeUpdateExpression() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $age_before = db_query('SELECT age FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetchField();    // This is a very contrived example, as I have no idea why you'd want to    // change age this way, but that's beside the point.    // Note that we are also double-setting age here, once as a literal and    // once as an expression. This test will only pass if the expression wins,    // which is what is supposed to happen.    db_merge('test_people')      ->key(array('job' => 'Speaker'))      ->fields(array('name' => 'Tiffany'))      ->insertFields(array('age' => 31))      ->expression('age', 'age + :age', array(':age' => 4))      ->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();    $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');    $this->assertEqual($person->age, $age_before + 4, 'Age updated correctly.');    $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');  }  /**   * Test that we can merge-insert without any update fields.   */  function testMergeInsertWithoutUpdate() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    db_merge('test_people')      ->key(array('job' => 'Presenter'))      ->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before + 1, $num_records_after, 'Merge inserted properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Presenter'))->fetch();    $this->assertEqual($person->name, '', 'Name set correctly.');    $this->assertEqual($person->age, 0, 'Age set correctly.');    $this->assertEqual($person->job, 'Presenter', 'Job set correctly.');  }  /**   * Confirm that we can merge-update without any update fields.   */  function testMergeUpdateWithoutUpdate() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    db_merge('test_people')      ->key(array('job' => 'Speaker'))      ->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after, 'Merge skipped properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();    $this->assertEqual($person->name, 'Meredith', 'Name skipped correctly.');    $this->assertEqual($person->age, 30, 'Age skipped correctly.');    $this->assertEqual($person->job, 'Speaker', 'Job skipped correctly.');    db_merge('test_people')      ->key(array('job' => 'Speaker'))      ->insertFields(array('age' => 31))      ->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();    $this->assertEqual($num_records_before, $num_records_after, 'Merge skipped properly.');    $person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();    $this->assertEqual($person->name, 'Meredith', 'Name skipped correctly.');    $this->assertEqual($person->age, 30, 'Age skipped correctly.');    $this->assertEqual($person->job, 'Speaker', 'Job skipped correctly.');  }  /**   * Test that an invalid merge query throws an exception like it is supposed to.   */  function testInvalidMerge() {    try {      // This query should die because there is no key field specified.      db_merge('test_people')        ->fields(array(          'age' => 31,          'name' => 'Tiffany',        ))        ->execute();    }    catch (InvalidMergeQueryException $e) {      $this->pass('InvalidMergeQueryException thrown for invalid query.');      return;    }    $this->fail('No InvalidMergeQueryException thrown');  }}/** * Test the SELECT builder. */class DatabaseSelectTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Select tests',      'description' => 'Test the Select query builder.',      'group' => 'Database',    );  }  /**   * Test rudimentary SELECT statements.   */  function testSimpleSelect() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $result = $query->execute();    $num_records = 0;    foreach ($result as $record) {      $num_records++;    }    $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');  }  /**   * Test rudimentary SELECT statement with a COMMENT.   */  function testSimpleComment() {    $query = db_select('test')->comment('Testing query comments');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $result = $query->execute();    $num_records = 0;    foreach ($result as $record) {      $num_records++;    }    $query = (string)$query;    $expected = "/* Testing query comments */ SELECT test.name AS name, test.age AS age\nFROM \n{test} test";    $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');    $this->assertEqual($query, $expected, 'The flattened query contains the comment string.');  }  /**   * Test query COMMENT system against vulnerabilities.   */  function testVulnerableComment() {    $query = db_select('test')->comment('Testing query comments */ SELECT nid FROM {node}; --');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $result = $query->execute();    $num_records = 0;    foreach ($result as $record) {      $num_records++;    }    $query = (string)$query;    $expected = "/* Testing query comments  * / SELECT nid FROM {node}; -- */ SELECT test.name AS name, test.age AS age\nFROM \n{test} test";    $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');    $this->assertEqual($query, $expected, 'The flattened query contains the sanitised comment string.');    $connection = Database::getConnection();    foreach ($this->makeCommentsProvider() as $test_set) {      list($expected, $comments) = $test_set;      $this->assertEqual($expected, $connection->makeComment($comments));    }  }  /**   * Provides expected and input values for testVulnerableComment().   */  function makeCommentsProvider() {    return array(      array(        '/*  */ ',        array(''),      ),      // Try and close the comment early.      array(        '/* Exploit  * / DROP TABLE node; -- */ ',        array('Exploit */ DROP TABLE node; --'),      ),      // Variations on comment closing.      array(        '/* Exploit  * / * / DROP TABLE node; -- */ ',        array('Exploit */*/ DROP TABLE node; --'),      ),      array(        '/* Exploit  *  * // DROP TABLE node; -- */ ',        array('Exploit **// DROP TABLE node; --'),      ),      // Try closing the comment in the second string which is appended.      array(        '/* Exploit  * / DROP TABLE node; --; Another try  * / DROP TABLE node; -- */ ',        array('Exploit */ DROP TABLE node; --', 'Another try */ DROP TABLE node; --'),      ),    );  }  /**   * Test basic conditionals on SELECT statements.   */  function testSimpleSelectConditional() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $query->condition('age', 27);    $result = $query->execute();    // Check that the aliases are being created the way we want.    $this->assertEqual($name_field, 'name', 'Name field alias is correct.');    $this->assertEqual($age_field, 'age', 'Age field alias is correct.');    // Ensure that we got the right record.    $record = $result->fetch();    $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');    $this->assertEqual($record->$age_field, 27, 'Fetched age is correct.');  }  /**   * Test SELECT statements with expressions.   */  function testSimpleSelectExpression() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addExpression("age*2", 'double_age');    $query->condition('age', 27);    $result = $query->execute();    // Check that the aliases are being created the way we want.    $this->assertEqual($name_field, 'name', 'Name field alias is correct.');    $this->assertEqual($age_field, 'double_age', 'Age field alias is correct.');    // Ensure that we got the right record.    $record = $result->fetch();    $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');    $this->assertEqual($record->$age_field, 27*2, 'Fetched age expression is correct.');  }  /**   * Test SELECT statements with multiple expressions.   */  function testSimpleSelectExpressionMultiple() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_double_field = $query->addExpression("age*2");    $age_triple_field = $query->addExpression("age*3");    $query->condition('age', 27);    $result = $query->execute();    // Check that the aliases are being created the way we want.    $this->assertEqual($age_double_field, 'expression', 'Double age field alias is correct.');    $this->assertEqual($age_triple_field, 'expression_2', 'Triple age field alias is correct.');    // Ensure that we got the right record.    $record = $result->fetch();    $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');    $this->assertEqual($record->$age_double_field, 27*2, 'Fetched double age expression is correct.');    $this->assertEqual($record->$age_triple_field, 27*3, 'Fetched triple age expression is correct.');  }  /**   * Test adding multiple fields to a select statement at the same time.   */  function testSimpleSelectMultipleFields() {    $record = db_select('test')      ->fields('test', array('id', 'name', 'age', 'job'))      ->condition('age', 27)      ->execute()->fetchObject();    // Check that all fields we asked for are present.    $this->assertNotNull($record->id, 'ID field is present.');    $this->assertNotNull($record->name, 'Name field is present.');    $this->assertNotNull($record->age, 'Age field is present.');    $this->assertNotNull($record->job, 'Job field is present.');    // Ensure that we got the right record.    // Check that all fields we asked for are present.    $this->assertEqual($record->id, 2, 'ID field has the correct value.');    $this->assertEqual($record->name, 'George', 'Name field has the correct value.');    $this->assertEqual($record->age, 27, 'Age field has the correct value.');    $this->assertEqual($record->job, 'Singer', 'Job field has the correct value.');  }  /**   * Test adding all fields from a given table to a select statement.   */  function testSimpleSelectAllFields() {    $record = db_select('test')      ->fields('test')      ->condition('age', 27)      ->execute()->fetchObject();    // Check that all fields we asked for are present.    $this->assertNotNull($record->id, 'ID field is present.');    $this->assertNotNull($record->name, 'Name field is present.');    $this->assertNotNull($record->age, 'Age field is present.');    $this->assertNotNull($record->job, 'Job field is present.');    // Ensure that we got the right record.    // Check that all fields we asked for are present.    $this->assertEqual($record->id, 2, 'ID field has the correct value.');    $this->assertEqual($record->name, 'George', 'Name field has the correct value.');    $this->assertEqual($record->age, 27, 'Age field has the correct value.');    $this->assertEqual($record->job, 'Singer', 'Job field has the correct value.');  }  /**   * Test that we can find a record with a NULL value.   */  function testNullCondition() {    $this->ensureSampleDataNull();    $names = db_select('test_null', 'tn')      ->fields('tn', array('name'))      ->isNull('age')      ->execute()->fetchCol();    $this->assertEqual(count($names), 1, 'Correct number of records found with NULL age.');    $this->assertEqual($names[0], 'Fozzie', 'Correct record returned for NULL age.');  }  /**   * Test that we can find a record without a NULL value.   */  function testNotNullCondition() {    $this->ensureSampleDataNull();    $names = db_select('test_null', 'tn')      ->fields('tn', array('name'))      ->isNotNull('tn.age')      ->orderBy('name')      ->execute()->fetchCol();    $this->assertEqual(count($names), 2, 'Correct number of records found withNOT NULL age.');    $this->assertEqual($names[0], 'Gonzo', 'Correct record returned for NOT NULL age.');    $this->assertEqual($names[1], 'Kermit', 'Correct record returned for NOT NULL age.');  }  /**   * Test that we can UNION multiple Select queries together. This is   * semantically equal to UNION DISTINCT, so we don't explicity test that.   */  function testUnion() {    $query_1 = db_select('test', 't')      ->fields('t', array('name'))      ->condition('age', array(27, 28), 'IN');    $query_2 = db_select('test', 't')      ->fields('t', array('name'))      ->condition('age', 28);    $query_1->union($query_2);    $names = $query_1->execute()->fetchCol();    // Ensure we only get 2 records.    $this->assertEqual(count($names), 2, 'UNION correctly discarded duplicates.');    $this->assertEqual($names[0], 'George', 'First query returned correct name.');    $this->assertEqual($names[1], 'Ringo', 'Second query returned correct name.');  }  /**   * Test that we can UNION ALL multiple Select queries together.   */  function testUnionAll() {    $query_1 = db_select('test', 't')      ->fields('t', array('name'))      ->condition('age', array(27, 28), 'IN');    $query_2 = db_select('test', 't')      ->fields('t', array('name'))      ->condition('age', 28);    $query_1->union($query_2, 'ALL');    $names = $query_1->execute()->fetchCol();    // Ensure we get all 3 records.    $this->assertEqual(count($names), 3, 'UNION ALL correctly preserved duplicates.');    $this->assertEqual($names[0], 'George', 'First query returned correct first name.');    $this->assertEqual($names[1], 'Ringo', 'Second query returned correct second name.');    $this->assertEqual($names[2], 'Ringo', 'Third query returned correct name.');  }  /**   * Test that random ordering of queries works.   *   * We take the approach of testing the Drupal layer only, rather than trying   * to test that the database's random number generator actually produces   * random queries (which is very difficult to do without an unacceptable risk   * of the test failing by accident).   *   * Therefore, in this test we simply run the same query twice and assert that   * the two results are reordered versions of each other (as well as of the   * same query without the random ordering). It is reasonable to assume that   * if we run the same select query twice and the results are in a different   * order each time, the only way this could happen is if we have successfully   * triggered the database's random ordering functionality.   */  function testRandomOrder() {    // Use 52 items, so the chance that this test fails by accident will be the    // same as the chance that a deck of cards will come out in the same order    // after shuffling it (in other words, nearly impossible).    $number_of_items = 52;    while (db_query("SELECT MAX(id) FROM {test}")->fetchField() < $number_of_items) {      db_insert('test')->fields(array('name' => $this->randomName()))->execute();    }    // First select the items in order and make sure we get an ordered list.    $expected_ids = range(1, $number_of_items);    $ordered_ids = db_select('test', 't')      ->fields('t', array('id'))      ->range(0, $number_of_items)      ->orderBy('id')      ->execute()      ->fetchCol();    $this->assertEqual($ordered_ids, $expected_ids, 'A query without random ordering returns IDs in the correct order.');    // Now perform the same query, but instead choose a random ordering. We    // expect this to contain a differently ordered version of the original    // result.    $randomized_ids = db_select('test', 't')      ->fields('t', array('id'))      ->range(0, $number_of_items)      ->orderRandom()      ->execute()      ->fetchCol();    $this->assertNotEqual($randomized_ids, $ordered_ids, 'A query with random ordering returns an unordered set of IDs.');    $sorted_ids = $randomized_ids;    sort($sorted_ids);    $this->assertEqual($sorted_ids, $ordered_ids, 'After sorting the random list, the result matches the original query.');    // Now perform the exact same query again, and make sure the order is    // different.    $randomized_ids_second_set = db_select('test', 't')      ->fields('t', array('id'))      ->range(0, $number_of_items)      ->orderRandom()      ->execute()      ->fetchCol();    $this->assertNotEqual($randomized_ids_second_set, $randomized_ids, 'Performing the query with random ordering a second time returns IDs in a different order.');    $sorted_ids_second_set = $randomized_ids_second_set;    sort($sorted_ids_second_set);    $this->assertEqual($sorted_ids_second_set, $sorted_ids, 'After sorting the second random list, the result matches the sorted version of the first random list.');  }  /**   * Test that aliases are renamed when duplicates.   */  function testSelectDuplicateAlias() {    $query = db_select('test', 't');    $alias1 = $query->addField('t', 'name', 'the_alias');    $alias2 = $query->addField('t', 'age', 'the_alias');    $this->assertNotIdentical($alias1, $alias2, 'Duplicate aliases are renamed.');  }}/** * Test case for subselects in a dynamic SELECT query. */class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Select tests, subqueries',      'description' => 'Test the Select query builder.',      'group' => 'Database',    );  }  /**   * Test that we can use a subquery in a FROM clause.   */  function testFromSubquerySelect() {    // Create a subquery, which is just a normal query object.    $subquery = db_select('test_task', 'tt');    $subquery->addField('tt', 'pid', 'pid');    $subquery->addField('tt', 'task', 'task');    $subquery->condition('priority', 1);    for ($i = 0; $i < 2; $i++) {      // Create another query that joins against the virtual table resulting      // from the subquery.      $select = db_select($subquery, 'tt2');      $select->join('test', 't', 't.id=tt2.pid');      $select->addField('t', 'name');      if ($i) {        // Use a different number of conditions here to confuse the subquery        // placeholder counter, testing http://drupal.org/node/1112854.        $select->condition('name', 'John');      }      $select->condition('task', 'code');      // The resulting query should be equivalent to:      // SELECT t.name      // FROM (SELECT tt.pid AS pid, tt.task AS task FROM test_task tt WHERE priority=1) tt      //   INNER JOIN test t ON t.id=tt.pid      // WHERE tt.task = 'code'      $people = $select->execute()->fetchCol();      $this->assertEqual(count($people), 1, 'Returned the correct number of rows.');    }  }  /**   * Test that we can use a subquery in a FROM clause with a limit.   */  function testFromSubquerySelectWithLimit() {    // Create a subquery, which is just a normal query object.    $subquery = db_select('test_task', 'tt');    $subquery->addField('tt', 'pid', 'pid');    $subquery->addField('tt', 'task', 'task');    $subquery->orderBy('priority', 'DESC');    $subquery->range(0, 1);    // Create another query that joins against the virtual table resulting    // from the subquery.    $select = db_select($subquery, 'tt2');    $select->join('test', 't', 't.id=tt2.pid');    $select->addField('t', 'name');    // The resulting query should be equivalent to:    // SELECT t.name    // FROM (SELECT tt.pid AS pid, tt.task AS task FROM test_task tt ORDER BY priority DESC LIMIT 1 OFFSET 0) tt    //   INNER JOIN test t ON t.id=tt.pid    $people = $select->execute()->fetchCol();    $this->assertEqual(count($people), 1, 'Returned the correct number of rows.');  }  /**   * Test that we can use a subquery in a WHERE clause.   */  function testConditionSubquerySelect() {    // Create a subquery, which is just a normal query object.    $subquery = db_select('test_task', 'tt');    $subquery->addField('tt', 'pid', 'pid');    $subquery->condition('tt.priority', 1);    // Create another query that joins against the virtual table resulting    // from the subquery.    $select = db_select('test_task', 'tt2');    $select->addField('tt2', 'task');    $select->condition('tt2.pid', $subquery, 'IN');    // The resulting query should be equivalent to:    // SELECT tt2.name    // FROM test tt2    // WHERE tt2.pid IN (SELECT tt.pid AS pid FROM test_task tt WHERE tt.priority=1)    $people = $select->execute()->fetchCol();    $this->assertEqual(count($people), 5, 'Returned the correct number of rows.');  }  /**   * Test that we can use a subquery in a JOIN clause.   */  function testJoinSubquerySelect() {    // Create a subquery, which is just a normal query object.    $subquery = db_select('test_task', 'tt');    $subquery->addField('tt', 'pid', 'pid');    $subquery->condition('priority', 1);    // Create another query that joins against the virtual table resulting    // from the subquery.    $select = db_select('test', 't');    $select->join($subquery, 'tt', 't.id=tt.pid');    $select->addField('t', 'name');    // The resulting query should be equivalent to:    // SELECT t.name    // FROM test t    //   INNER JOIN (SELECT tt.pid AS pid FROM test_task tt WHERE priority=1) tt ON t.id=tt.pid    $people = $select->execute()->fetchCol();    $this->assertEqual(count($people), 2, 'Returned the correct number of rows.');  }  /**   * Test EXISTS subquery conditionals on SELECT statements.   *   * We essentially select all rows from the {test} table that have matching   * rows in the {test_people} table based on the shared name column.   */  function testExistsSubquerySelect() {    // Put George into {test_people}.    db_insert('test_people')      ->fields(array(        'name' => 'George',        'age' => 27,        'job' => 'Singer',      ))      ->execute();    // Base query to {test}.    $query = db_select('test', 't')      ->fields('t', array('name'));    // Subquery to {test_people}.    $subquery = db_select('test_people', 'tp')      ->fields('tp', array('name'))      ->where('tp.name = t.name');    $query->exists($subquery);    $result = $query->execute();    // Ensure that we got the right record.    $record = $result->fetch();    $this->assertEqual($record->name, 'George', 'Fetched name is correct using EXISTS query.');  }  /**   * Test NOT EXISTS subquery conditionals on SELECT statements.   *   * We essentially select all rows from the {test} table that don't have   * matching rows in the {test_people} table based on the shared name column.   */  function testNotExistsSubquerySelect() {    // Put George into {test_people}.    db_insert('test_people')      ->fields(array(        'name' => 'George',        'age' => 27,        'job' => 'Singer',      ))      ->execute();    // Base query to {test}.    $query = db_select('test', 't')      ->fields('t', array('name'));    // Subquery to {test_people}.    $subquery = db_select('test_people', 'tp')      ->fields('tp', array('name'))      ->where('tp.name = t.name');    $query->notExists($subquery);    // Ensure that we got the right number of records.    $people = $query->execute()->fetchCol();    $this->assertEqual(count($people), 3, 'NOT EXISTS query returned the correct results.');  }}/** * Test select with order by clauses. */class DatabaseSelectOrderedTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Select tests, ordered',      'description' => 'Test the Select query builder.',      'group' => 'Database',    );  }  /**   * Test basic order by.   */  function testSimpleSelectOrdered() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $query->orderBy($age_field);    $result = $query->execute();    $num_records = 0;    $last_age = 0;    foreach ($result as $record) {      $num_records++;      $this->assertTrue($record->age >= $last_age, 'Results returned in correct order.');      $last_age = $record->age;    }    $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');  }  /**   * Test multiple order by.   */  function testSimpleSelectMultiOrdered() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $job_field = $query->addField('test', 'job');    $query->orderBy($job_field);    $query->orderBy($age_field);    $result = $query->execute();    $num_records = 0;    $expected = array(      array('Ringo', 28, 'Drummer'),      array('John', 25, 'Singer'),      array('George', 27, 'Singer'),      array('Paul', 26, 'Songwriter'),    );    $results = $result->fetchAll(PDO::FETCH_NUM);    foreach ($expected as $k => $record) {      $num_records++;      foreach ($record as $kk => $col) {        if ($expected[$k][$kk] != $results[$k][$kk]) {          $this->assertTrue(FALSE, 'Results returned in correct order.');        }      }    }    $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');  }  /**   * Test order by descending.   */  function testSimpleSelectOrderedDesc() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $query->orderBy($age_field, 'DESC');    $result = $query->execute();    $num_records = 0;    $last_age = 100000000;    foreach ($result as $record) {      $num_records++;      $this->assertTrue($record->age <= $last_age, 'Results returned in correct order.');      $last_age = $record->age;    }    $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');  }  /**   * Tests that the sort direction is sanitized properly.   */  function testOrderByEscaping() {    $query = db_select('test')->orderBy('name', 'invalid direction');    $order_bys = $query->getOrderBy();    $this->assertEqual($order_bys['name'], 'ASC', 'Invalid order by direction is converted to ASC.');  }}/** * Test more complex select statements. */class DatabaseSelectComplexTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Select tests, complex',      'description' => 'Test the Select query builder with more complex queries.',      'group' => 'Database',    );  }  /**   * Test simple JOIN statements.   */  function testDefaultJoin() {    $query = db_select('test_task', 't');    $people_alias = $query->join('test', 'p', 't.pid = p.id');    $name_field = $query->addField($people_alias, 'name', 'name');    $task_field = $query->addField('t', 'task', 'task');    $priority_field = $query->addField('t', 'priority', 'priority');    $query->orderBy($priority_field);    $result = $query->execute();    $num_records = 0;    $last_priority = 0;    foreach ($result as $record) {      $num_records++;      $this->assertTrue($record->$priority_field >= $last_priority, 'Results returned in correct order.');      $this->assertNotEqual($record->$name_field, 'Ringo', 'Taskless person not selected.');      $last_priority = $record->$priority_field;    }    $this->assertEqual($num_records, 7, 'Returned the correct number of rows.');  }  /**   * Test LEFT OUTER joins.   */  function testLeftOuterJoin() {    $query = db_select('test', 'p');    $people_alias = $query->leftJoin('test_task', 't', 't.pid = p.id');    $name_field = $query->addField('p', 'name', 'name');    $task_field = $query->addField($people_alias, 'task', 'task');    $priority_field = $query->addField($people_alias, 'priority', 'priority');    $query->orderBy($name_field);    $result = $query->execute();    $num_records = 0;    $last_name = 0;    foreach ($result as $record) {      $num_records++;      $this->assertTrue(strcmp($record->$name_field, $last_name) >= 0, 'Results returned in correct order.');      $last_priority = $record->$name_field;    }    $this->assertEqual($num_records, 8, 'Returned the correct number of rows.');  }  /**   * Test GROUP BY clauses.   */  function testGroupBy() {    $query = db_select('test_task', 't');    $count_field = $query->addExpression('COUNT(task)', 'num');    $task_field = $query->addField('t', 'task');    $query->orderBy($count_field);    $query->groupBy($task_field);    $result = $query->execute();    $num_records = 0;    $last_count = 0;    $records = array();    foreach ($result as $record) {      $num_records++;      $this->assertTrue($record->$count_field >= $last_count, 'Results returned in correct order.');      $last_count = $record->$count_field;      $records[$record->$task_field] = $record->$count_field;    }    $correct_results = array(      'eat' => 1,      'sleep' => 2,      'code' => 1,      'found new band' => 1,      'perform at superbowl' => 1,    );    foreach ($correct_results as $task => $count) {      $this->assertEqual($records[$task], $count, format_string("Correct number of '@task' records found.", array('@task' => $task)));    }    $this->assertEqual($num_records, 6, 'Returned the correct number of total rows.');  }  /**   * Test GROUP BY and HAVING clauses together.   */  function testGroupByAndHaving() {    $query = db_select('test_task', 't');    $count_field = $query->addExpression('COUNT(task)', 'num');    $task_field = $query->addField('t', 'task');    $query->orderBy($count_field);    $query->groupBy($task_field);    $query->having('COUNT(task) >= 2');    $result = $query->execute();    $num_records = 0;    $last_count = 0;    $records = array();    foreach ($result as $record) {      $num_records++;      $this->assertTrue($record->$count_field >= 2, 'Record has the minimum count.');      $this->assertTrue($record->$count_field >= $last_count, 'Results returned in correct order.');      $last_count = $record->$count_field;      $records[$record->$task_field] = $record->$count_field;    }    $correct_results = array(      'sleep' => 2,    );    foreach ($correct_results as $task => $count) {      $this->assertEqual($records[$task], $count, format_string("Correct number of '@task' records found.", array('@task' => $task)));    }    $this->assertEqual($num_records, 1, 'Returned the correct number of total rows.');  }  /**   * Test range queries. The SQL clause varies with the database.   */  function testRange() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $query->range(0, 2);    $result = $query->execute();    $num_records = 0;    foreach ($result as $record) {      $num_records++;    }    $this->assertEqual($num_records, 2, 'Returned the correct number of rows.');  }  /**   * Test distinct queries.   */  function testDistinct() {    $query = db_select('test_task');    $task_field = $query->addField('test_task', 'task');    $query->distinct();    $result = $query->execute();    $num_records = 0;    foreach ($result as $record) {      $num_records++;    }    $this->assertEqual($num_records, 6, 'Returned the correct number of rows.');  }  /**   * Test that we can generate a count query from a built query.   */  function testCountQuery() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $query->orderBy('name');    $count = $query->countQuery()->execute()->fetchField();    $this->assertEqual($count, 4, 'Counted the correct number of records.');    // Now make sure we didn't break the original query!  We should still have    // all of the fields we asked for.    $record = $query->execute()->fetch();    $this->assertEqual($record->$name_field, 'George', 'Correct data retrieved.');    $this->assertEqual($record->$age_field, 27, 'Correct data retrieved.');  }  function testHavingCountQuery() {    $query = db_select('test')      ->extend('PagerDefault')      ->groupBy('age')      ->having('age + 1 > 0');    $query->addField('test', 'age');    $query->addExpression('age + 1');    $count = count($query->execute()->fetchCol());    $this->assertEqual($count, 4, 'Counted the correct number of records.');  }  /**   * Test that countQuery properly removes 'all_fields' statements and   * ordering clauses.   */  function testCountQueryRemovals() {    $query = db_select('test');    $query->fields('test');    $query->orderBy('name');    $count = $query->countQuery();    // Check that the 'all_fields' statement is handled properly.    $tables = $query->getTables();    $this->assertEqual($tables['test']['all_fields'], 1, 'Query correctly sets \'all_fields\' statement.');    $tables = $count->getTables();    $this->assertFalse(isset($tables['test']['all_fields']), 'Count query correctly unsets \'all_fields\' statement.');    // Check that the ordering clause is handled properly.    $orderby = $query->getOrderBy();    $this->assertEqual($orderby['name'], 'ASC', 'Query correctly sets ordering clause.');    $orderby = $count->getOrderBy();    $this->assertFalse(isset($orderby['name']), 'Count query correctly unsets ordering caluse.');    // Make sure that the count query works.    $count = $count->execute()->fetchField();    $this->assertEqual($count, 4, 'Counted the correct number of records.');  }  /**   * Test that countQuery properly removes fields and expressions.   */  function testCountQueryFieldRemovals() {    // countQuery should remove all fields and expressions, so this can be    // tested by adding a non-existent field and expression: if it ends    // up in the query, an error will be thrown. If not, it will return the    // number of records, which in this case happens to be 4 (there are four    // records in the {test} table).    $query = db_select('test');    $query->fields('test', array('fail'));    $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), 'Count Query removed fields');    $query = db_select('test');    $query->addExpression('fail');    $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), 'Count Query removed expressions');  }  /**   * Test that we can generate a count query from a query with distinct.   */  function testCountQueryDistinct() {    $query = db_select('test_task');    $task_field = $query->addField('test_task', 'task');    $query->distinct();    $count = $query->countQuery()->execute()->fetchField();    $this->assertEqual($count, 6, 'Counted the correct number of records.');  }  /**   * Test that we can generate a count query from a query with GROUP BY.   */  function testCountQueryGroupBy() {    $query = db_select('test_task');    $pid_field = $query->addField('test_task', 'pid');    $query->groupBy('pid');    $count = $query->countQuery()->execute()->fetchField();    $this->assertEqual($count, 3, 'Counted the correct number of records.');    // Use a column alias as, without one, the query can succeed for the wrong    // reason.    $query = db_select('test_task');    $pid_field = $query->addField('test_task', 'pid', 'pid_alias');    $query->addExpression('COUNT(test_task.task)', 'count');    $query->groupBy('pid_alias');    $query->orderBy('pid_alias', 'asc');    $count = $query->countQuery()->execute()->fetchField();    $this->assertEqual($count, 3, 'Counted the correct number of records.');  }  /**   * Confirm that we can properly nest conditional clauses.   */  function testNestedConditions() {    // This query should translate to:    // "SELECT job FROM {test} WHERE name = 'Paul' AND (age = 26 OR age = 27)"    // That should find only one record. Yes it's a non-optimal way of writing    // that query but that's not the point!    $query = db_select('test');    $query->addField('test', 'job');    $query->condition('name', 'Paul');    $query->condition(db_or()->condition('age', 26)->condition('age', 27));    $job = $query->execute()->fetchField();    $this->assertEqual($job, 'Songwriter', 'Correct data retrieved.');  }  /**   * Confirm we can join on a single table twice with a dynamic alias.   */  function testJoinTwice() {    $query = db_select('test')->fields('test');    $alias = $query->join('test', 'test', 'test.job = %alias.job');    $query->addField($alias, 'name', 'othername');    $query->addField($alias, 'job', 'otherjob');    $query->where("$alias.name <> test.name");    $crowded_job = $query->execute()->fetch();    $this->assertEqual($crowded_job->job, $crowded_job->otherjob, 'Correctly joined same table twice.');    $this->assertNotEqual($crowded_job->name, $crowded_job->othername, 'Correctly joined same table twice.');  }}/** * Test more complex select statements, part 2. */class DatabaseSelectComplexTestCase2 extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Select tests, complex 2',      'description' => 'Test the Select query builder with even more complex queries.',      'group' => 'Database',    );  }  function setUp() {    DrupalWebTestCase::setUp('database_test', 'node_access_test');    $schema['test'] = drupal_get_schema('test');    $schema['test_people'] = drupal_get_schema('test_people');    $schema['test_one_blob'] = drupal_get_schema('test_one_blob');    $schema['test_two_blobs'] = drupal_get_schema('test_two_blobs');    $schema['test_task'] = drupal_get_schema('test_task');    $this->installTables($schema);    $this->addSampleData();  }  /**   * Test that we can join on a query.   */  function testJoinSubquery() {    $acct = $this->drupalCreateUser(array('access content'));    $this->drupalLogin($acct);    $query = db_select('test_task', 'tt', array('target' => 'slave'));    $query->addExpression('tt.pid + 1', 'abc');    $query->condition('priority', 1, '>');    $query->condition('priority', 100, '<');    $subquery = db_select('test', 'tp');    $subquery->join('test_one_blob', 'tpb', 'tp.id = tpb.id');    $subquery->join('node', 'n', 'tp.id = n.nid');    $subquery->addTag('node_access');    $subquery->addMetaData('account', $acct);    $subquery->addField('tp', 'id');    $subquery->condition('age', 5, '>');    $subquery->condition('age', 500, '<');    $query->leftJoin($subquery, 'sq', 'tt.pid = sq.id');    $query->join('test_one_blob', 'tb3', 'tt.pid = tb3.id');    // Construct the query string.    // This is the same sequence that SelectQuery::execute() goes through.    $query->preExecute();    $query->getArguments();    $str = (string) $query;    // Verify that the string only has one copy of condition placeholder 0.    $pos = strpos($str, 'db_condition_placeholder_0', 0);    $pos2 = strpos($str, 'db_condition_placeholder_0', $pos + 1);    $this->assertFalse($pos2, 'Condition placeholder is not repeated.');  }}class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Pager query tests',      'description' => 'Test the pager query extender.',      'group' => 'Database',    );  }  /**   * Confirm that a pager query returns the correct results.   *   * Note that we have to make an HTTP request to a test page handler   * because the pager depends on GET parameters.   */  function testEvenPagerQuery() {    // To keep the test from being too brittle, we determine up front    // what the page count should be dynamically, and pass the control    // information forward to the actual query on the other side of the    // HTTP request.    $limit = 2;    $count = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $correct_number = $limit;    $num_pages = floor($count / $limit);    // If there is no remainder from rounding, subtract 1 since we index from 0.    if (!($num_pages * $limit < $count)) {      $num_pages--;    }    for ($page = 0; $page <= $num_pages; ++$page) {      $this->drupalGet('database_test/pager_query_even/' . $limit, array('query' => array('page' => $page)));      $data = json_decode($this->drupalGetContent());      if ($page == $num_pages) {        $correct_number = $count - ($limit * $page);      }      $this->assertEqual(count($data->names), $correct_number, format_string('Correct number of records returned by pager: @number', array('@number' => $correct_number)));    }  }  /**   * Confirm that a pager query returns the correct results.   *   * Note that we have to make an HTTP request to a test page handler   * because the pager depends on GET parameters.   */  function testOddPagerQuery() {    // To keep the test from being too brittle, we determine up front    // what the page count should be dynamically, and pass the control    // information forward to the actual query on the other side of the    // HTTP request.    $limit = 2;    $count = db_query('SELECT COUNT(*) FROM {test_task}')->fetchField();    $correct_number = $limit;    $num_pages = floor($count / $limit);    // If there is no remainder from rounding, subtract 1 since we index from 0.    if (!($num_pages * $limit < $count)) {      $num_pages--;    }    for ($page = 0; $page <= $num_pages; ++$page) {      $this->drupalGet('database_test/pager_query_odd/' . $limit, array('query' => array('page' => $page)));      $data = json_decode($this->drupalGetContent());      if ($page == $num_pages) {        $correct_number = $count - ($limit * $page);      }      $this->assertEqual(count($data->names), $correct_number, format_string('Correct number of records returned by pager: @number', array('@number' => $correct_number)));    }  }  /**   * Confirm that a pager query with inner pager query returns valid results.   *   * This is a regression test for #467984.   */  function testInnerPagerQuery() {    $query = db_select('test', 't')->extend('PagerDefault');    $query      ->fields('t', array('age'))      ->orderBy('age')      ->limit(5);    $outer_query = db_select($query);    $outer_query->addField('subquery', 'age');    $ages = $outer_query      ->execute()      ->fetchCol();    $this->assertEqual($ages, array(25, 26, 27, 28), 'Inner pager query returned the correct ages.');  }  /**   * Confirm that a paging query with a having expression returns valid results.   *   * This is a regression test for #467984.   */  function testHavingPagerQuery() {    $query = db_select('test', 't')->extend('PagerDefault');    $query      ->fields('t', array('name'))      ->orderBy('name')      ->groupBy('name')      ->having('MAX(age) > :count', array(':count' => 26))      ->limit(5);    $ages = $query      ->execute()      ->fetchCol();    $this->assertEqual($ages, array('George', 'Ringo'), 'Pager query with having expression returned the correct ages.');  }  /**   * Confirm that every pager gets a valid non-overlaping element ID.   */  function testElementNumbers() {    $_GET['page'] = '3, 2, 1, 0';    $name = db_select('test', 't')->extend('PagerDefault')      ->element(2)      ->fields('t', array('name'))      ->orderBy('age')      ->limit(1)      ->execute()      ->fetchField();    $this->assertEqual($name, 'Paul', 'Pager query #1 with a specified element ID returned the correct results.');    // Setting an element smaller than the previous one    // should not overwrite the pager $maxElement with a smaller value.    $name = db_select('test', 't')->extend('PagerDefault')      ->element(1)      ->fields('t', array('name'))      ->orderBy('age')      ->limit(1)      ->execute()      ->fetchField();    $this->assertEqual($name, 'George', 'Pager query #2 with a specified element ID returned the correct results.');    $name = db_select('test', 't')->extend('PagerDefault')      ->fields('t', array('name'))      ->orderBy('age')      ->limit(1)      ->execute()      ->fetchField();    $this->assertEqual($name, 'John', 'Pager query #3 with a generated element ID returned the correct results.');    unset($_GET['page']);  }}class DatabaseSelectTableSortDefaultTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Tablesort query tests',      'description' => 'Test the tablesort query extender.',      'group' => 'Database',    );  }  /**   * Confirm that a tablesort query returns the correct results.   *   * Note that we have to make an HTTP request to a test page handler   * because the pager depends on GET parameters.   */  function testTableSortQuery() {    $sorts = array(      array('field' => t('Task ID'), 'sort' => 'desc', 'first' => 'perform at superbowl', 'last' => 'eat'),      array('field' => t('Task ID'), 'sort' => 'asc', 'first' => 'eat', 'last' => 'perform at superbowl'),      array('field' => t('Task'), 'sort' => 'asc', 'first' => 'code', 'last' => 'sleep'),      array('field' => t('Task'), 'sort' => 'desc', 'first' => 'sleep', 'last' => 'code'),      // more elements here    );    foreach ($sorts as $sort) {      $this->drupalGet('database_test/tablesort/', array('query' => array('order' => $sort['field'], 'sort' => $sort['sort'])));      $data = json_decode($this->drupalGetContent());      $first = array_shift($data->tasks);      $last = array_pop($data->tasks);      $this->assertEqual($first->task, $sort['first'], 'Items appear in the correct order.');      $this->assertEqual($last->task, $sort['last'], 'Items appear in the correct order.');    }  }  /**   * Confirm that if a tablesort's orderByHeader is called before another orderBy, that the header happens first.   *   */  function testTableSortQueryFirst() {    $sorts = array(      array('field' => t('Task ID'), 'sort' => 'desc', 'first' => 'perform at superbowl', 'last' => 'eat'),      array('field' => t('Task ID'), 'sort' => 'asc', 'first' => 'eat', 'last' => 'perform at superbowl'),      array('field' => t('Task'), 'sort' => 'asc', 'first' => 'code', 'last' => 'sleep'),      array('field' => t('Task'), 'sort' => 'desc', 'first' => 'sleep', 'last' => 'code'),      // more elements here    );    foreach ($sorts as $sort) {      $this->drupalGet('database_test/tablesort_first/', array('query' => array('order' => $sort['field'], 'sort' => $sort['sort'])));      $data = json_decode($this->drupalGetContent());      $first = array_shift($data->tasks);      $last = array_pop($data->tasks);      $this->assertEqual($first->task, $sort['first'], format_string('Items appear in the correct order sorting by @field @sort.', array('@field' => $sort['field'], '@sort' => $sort['sort'])));      $this->assertEqual($last->task, $sort['last'], format_string('Items appear in the correct order sorting by @field @sort.', array('@field' => $sort['field'], '@sort' => $sort['sort'])));    }  }  /**   * Confirm that if a sort is not set in a tableselect form there is no error thrown when using the default.   */  function testTableSortDefaultSort() {    $this->drupalGet('database_test/tablesort_default_sort');    // Any PHP errors or notices thrown would trigger a simpletest exception, so    // no additional assertions are needed.  }}/** * Select tagging tests. * * Tags are a way to flag queries for alter hooks so they know * what type of query it is, such as "node_access". */class DatabaseTaggingTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Query tagging tests',      'description' => 'Test the tagging capabilities of the Select builder.',      'group' => 'Database',    );  }  /**   * Confirm that a query has a "tag" added to it.   */  function testHasTag() {    $query = db_select('test');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->addTag('test');    $this->assertTrue($query->hasTag('test'), 'hasTag() returned true.');    $this->assertFalse($query->hasTag('other'), 'hasTag() returned false.');  }  /**   * Test query tagging "has all of these tags" functionality.   */  function testHasAllTags() {    $query = db_select('test');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->addTag('test');    $query->addTag('other');    $this->assertTrue($query->hasAllTags('test', 'other'), 'hasAllTags() returned true.');    $this->assertFalse($query->hasAllTags('test', 'stuff'), 'hasAllTags() returned false.');  }  /**   * Test query tagging "has at least one of these tags" functionality.   */  function testHasAnyTag() {    $query = db_select('test');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->addTag('test');    $this->assertTrue($query->hasAnyTag('test', 'other'), 'hasAnyTag() returned true.');    $this->assertFalse($query->hasAnyTag('other', 'stuff'), 'hasAnyTag() returned false.');  }  /**   * Confirm that an extended query has a "tag" added to it.   */  function testExtenderHasTag() {    $query = db_select('test')      ->extend('SelectQueryExtender');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->addTag('test');    $this->assertTrue($query->hasTag('test'), 'hasTag() returned true.');    $this->assertFalse($query->hasTag('other'), 'hasTag() returned false.');  }  /**   * Test extended query tagging "has all of these tags" functionality.   */  function testExtenderHasAllTags() {    $query = db_select('test')      ->extend('SelectQueryExtender');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->addTag('test');    $query->addTag('other');    $this->assertTrue($query->hasAllTags('test', 'other'), 'hasAllTags() returned true.');    $this->assertFalse($query->hasAllTags('test', 'stuff'), 'hasAllTags() returned false.');  }  /**   * Test extended query tagging "has at least one of these tags" functionality.   */  function testExtenderHasAnyTag() {    $query = db_select('test')      ->extend('SelectQueryExtender');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->addTag('test');    $this->assertTrue($query->hasAnyTag('test', 'other'), 'hasAnyTag() returned true.');    $this->assertFalse($query->hasAnyTag('other', 'stuff'), 'hasAnyTag() returned false.');  }  /**   * Test that we can attach meta data to a query object.   *   * This is how we pass additional context to alter hooks.   */  function testMetaData() {    $query = db_select('test');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $data = array(      'a' => 'A',      'b' => 'B',    );    $query->addMetaData('test', $data);    $return = $query->getMetaData('test');    $this->assertEqual($data, $return, 'Corect metadata returned.');    $return = $query->getMetaData('nothere');    $this->assertNull($return, 'Non-existent key returned NULL.');  }}/** * Select alter tests. * * @see database_test_query_alter() */class DatabaseAlterTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Query altering tests',      'description' => 'Test the hook_query_alter capabilities of the Select builder.',      'group' => 'Database',    );  }  /**   * Test that we can do basic alters.   */  function testSimpleAlter() {    $query = db_select('test');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->addTag('database_test_alter_add_range');    $result = $query->execute();    $num_records = 0;    foreach ($result as $record) {      $num_records++;    }    $this->assertEqual($num_records, 2, 'Returned the correct number of rows.');  }  /**   * Test that we can alter the joins on a query.   */  function testAlterWithJoin() {    $query = db_select('test_task');    $tid_field = $query->addField('test_task', 'tid');    $task_field = $query->addField('test_task', 'task');    $query->orderBy($task_field);    $query->addTag('database_test_alter_add_join');    $result = $query->execute();    $records = $result->fetchAll();    $this->assertEqual(count($records), 2, 'Returned the correct number of rows.');    $this->assertEqual($records[0]->name, 'George', 'Correct data retrieved.');    $this->assertEqual($records[0]->$tid_field, 4, 'Correct data retrieved.');    $this->assertEqual($records[0]->$task_field, 'sing', 'Correct data retrieved.');    $this->assertEqual($records[1]->name, 'George', 'Correct data retrieved.');    $this->assertEqual($records[1]->$tid_field, 5, 'Correct data retrieved.');    $this->assertEqual($records[1]->$task_field, 'sleep', 'Correct data retrieved.');  }  /**   * Test that we can alter a query's conditionals.   */  function testAlterChangeConditional() {    $query = db_select('test_task');    $tid_field = $query->addField('test_task', 'tid');    $pid_field = $query->addField('test_task', 'pid');    $task_field = $query->addField('test_task', 'task');    $people_alias = $query->join('test', 'people', "test_task.pid = people.id");    $name_field = $query->addField($people_alias, 'name', 'name');    $query->condition('test_task.tid', '1');    $query->orderBy($tid_field);    $query->addTag('database_test_alter_change_conditional');    $result = $query->execute();    $records = $result->fetchAll();    $this->assertEqual(count($records), 1, 'Returned the correct number of rows.');    $this->assertEqual($records[0]->$name_field, 'John', 'Correct data retrieved.');    $this->assertEqual($records[0]->$tid_field, 2, 'Correct data retrieved.');    $this->assertEqual($records[0]->$pid_field, 1, 'Correct data retrieved.');    $this->assertEqual($records[0]->$task_field, 'sleep', 'Correct data retrieved.');  }  /**   * Test that we can alter the fields of a query.   */  function testAlterChangeFields() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addField('test', 'age', 'age');    $query->orderBy('name');    $query->addTag('database_test_alter_change_fields');    $record = $query->execute()->fetch();    $this->assertEqual($record->$name_field, 'George', 'Correct data retrieved.');    $this->assertFalse(isset($record->$age_field), 'Age field not found, as intended.');  }  /**   * Test that we can alter expressions in the query.   */  function testAlterExpression() {    $query = db_select('test');    $name_field = $query->addField('test', 'name');    $age_field = $query->addExpression("age*2", 'double_age');    $query->condition('age', 27);    $query->addTag('database_test_alter_change_expressions');    $result = $query->execute();    // Ensure that we got the right record.    $record = $result->fetch();    $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');    $this->assertEqual($record->$age_field, 27*3, 'Fetched age expression is correct.');  }  /**   * Test that we can remove a range() value from a query. This also tests hook_query_TAG_alter().   */  function testAlterRemoveRange() {    $query = db_select('test');    $query->addField('test', 'name');    $query->addField('test', 'age', 'age');    $query->range(0, 2);    $query->addTag('database_test_alter_remove_range');    $num_records = count($query->execute()->fetchAll());    $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');  }  /**   * Test that we can do basic alters on subqueries.   */  function testSimpleAlterSubquery() {    // Create a sub-query with an alter tag.    $subquery = db_select('test', 'p');    $subquery->addField('p', 'name');    $subquery->addField('p', 'id');    // Pick out George.    $subquery->condition('age', 27);    $subquery->addExpression("age*2", 'double_age');    // This query alter should change it to age * 3.    $subquery->addTag('database_test_alter_change_expressions');    // Create a main query and join to sub-query.    $query = db_select('test_task', 'tt');    $query->join($subquery, 'pq', 'pq.id = tt.pid');    $age_field = $query->addField('pq', 'double_age');    $name_field = $query->addField('pq', 'name');    $record = $query->execute()->fetch();    $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');    $this->assertEqual($record->$age_field, 27*3, 'Fetched age expression is correct.');  }}/** * Regression tests. */class DatabaseRegressionTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Regression tests',      'description' => 'Regression tests cases for the database layer.',      'group' => 'Database',    );  }  /**   * Regression test for #310447.   *   * Tries to insert non-ascii UTF-8 data in a database column and checks   * if its stored properly.   */  function testRegression_310447() {    // That's a 255 character UTF-8 string.    $name = str_repeat("é", 255);    db_insert('test')      ->fields(array(        'name' => $name,        'age' => 20,        'job' => 'Dancer',      ))->execute();    $from_database = db_query('SELECT name FROM {test} WHERE name = :name', array(':name' => $name))->fetchField();    $this->assertIdentical($name, $from_database, "The database handles UTF-8 characters cleanly.");  }  /**   * Test the db_table_exists() function.   */  function testDBTableExists() {    $this->assertIdentical(TRUE, db_table_exists('node'), 'Returns true for existent table.');    $this->assertIdentical(FALSE, db_table_exists('nosuchtable'), 'Returns false for nonexistent table.');  }  /**   * Test the db_field_exists() function.   */  function testDBFieldExists() {    $this->assertIdentical(TRUE, db_field_exists('node', 'nid'), 'Returns true for existent column.');    $this->assertIdentical(FALSE, db_field_exists('node', 'nosuchcolumn'), 'Returns false for nonexistent column.');  }  /**   * Test the db_index_exists() function.   */  function testDBIndexExists() {    $this->assertIdentical(TRUE, db_index_exists('node', 'node_created'), 'Returns true for existent index.');    $this->assertIdentical(FALSE, db_index_exists('node', 'nosuchindex'), 'Returns false for nonexistent index.');  }}/** * Query logging tests. */class DatabaseLoggingTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Query logging',      'description' => 'Test the query logging facility.',      'group' => 'Database',    );  }  /**   * Test that we can log the existence of a query.   */  function testEnableLogging() {    $log = Database::startLog('testing');    db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25))->fetchCol();    db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetchCol();    // Trigger a call that does not have file in the backtrace.    call_user_func_array('db_query', array('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo')))->fetchCol();    $queries = Database::getLog('testing', 'default');    $this->assertEqual(count($queries), 3, 'Correct number of queries recorded.');    foreach ($queries as $query) {      $this->assertEqual($query['caller']['function'], __FUNCTION__, 'Correct function in query log.');    }  }  /**   * Test that we can run two logs in parallel.   */  function testEnableMultiLogging() {    Database::startLog('testing1');    db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25))->fetchCol();    Database::startLog('testing2');    db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetchCol();    $queries1 = Database::getLog('testing1');    $queries2 = Database::getLog('testing2');    $this->assertEqual(count($queries1), 2, 'Correct number of queries recorded for log 1.');    $this->assertEqual(count($queries2), 1, 'Correct number of queries recorded for log 2.');  }  /**   * Test that we can log queries against multiple targets on the same connection.   */  function testEnableTargetLogging() {    // Clone the master credentials to a slave connection and to another fake    // connection.    $connection_info = Database::getConnectionInfo('default');    Database::addConnectionInfo('default', 'slave', $connection_info['default']);    Database::startLog('testing1');    db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25))->fetchCol();    db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'), array('target' => 'slave'));//->fetchCol();    $queries1 = Database::getLog('testing1');    $this->assertEqual(count($queries1), 2, 'Recorded queries from all targets.');    $this->assertEqual($queries1[0]['target'], 'default', 'First query used default target.');    $this->assertEqual($queries1[1]['target'], 'slave', 'Second query used slave target.');  }  /**   * Test that logs to separate targets collapse to the same connection properly.   *   * This test is identical to the one above, except that it doesn't create   * a fake target so the query should fall back to running on the default   * target.   */  function testEnableTargetLoggingNoTarget() {    Database::startLog('testing1');    db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25))->fetchCol();    // We use "fake" here as a target because any non-existent target will do.    // However, because all of the tests in this class share a single page    // request there is likely to be a target of "slave" from one of the other    // unit tests, so we use a target here that we know with absolute certainty    // does not exist.    db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'), array('target' => 'fake'))->fetchCol();    $queries1 = Database::getLog('testing1');    $this->assertEqual(count($queries1), 2, 'Recorded queries from all targets.');    $this->assertEqual($queries1[0]['target'], 'default', 'First query used default target.');    $this->assertEqual($queries1[1]['target'], 'default', 'Second query used default target as fallback.');  }  /**   * Test that we can log queries separately on different connections.   */  function testEnableMultiConnectionLogging() {    // Clone the master credentials to a fake connection.    // That both connections point to the same physical database is irrelevant.    $connection_info = Database::getConnectionInfo('default');    Database::addConnectionInfo('test2', 'default', $connection_info['default']);    Database::startLog('testing1');    Database::startLog('testing1', 'test2');    db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25))->fetchCol();    $old_key = db_set_active('test2');    db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'), array('target' => 'slave'))->fetchCol();    db_set_active($old_key);    $queries1 = Database::getLog('testing1');    $queries2 = Database::getLog('testing1', 'test2');    $this->assertEqual(count($queries1), 1, 'Correct number of queries recorded for first connection.');    $this->assertEqual(count($queries2), 1, 'Correct number of queries recorded for second connection.');  }}/** * Query serialization tests. */class DatabaseSerializeQueryTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Serialize query',      'description' => 'Test serializing and unserializing a query.',      'group' => 'Database',    );  }  /**   * Confirm that a query can be serialized and unserialized.   */  function testSerializeQuery() {    $query = db_select('test');    $query->addField('test', 'age');    $query->condition('name', 'Ringo');    // If this doesn't work, it will throw an exception, so no need for an    // assertion.    $query = unserialize(serialize($query));    $results = $query->execute()->fetchCol();    $this->assertEqual($results[0], 28, 'Query properly executed after unserialization.');  }}/** * Range query tests. */class DatabaseRangeQueryTestCase extends DrupalWebTestCase {  public static function getInfo() {    return array(      'name' => 'Range query test',      'description' => 'Test the Range query functionality.',      'group' => 'Database',    );  }  function setUp() {    parent::setUp('database_test');  }  /**   * Confirm that range query work and return correct result.   */  function testRangeQuery() {    // Test if return correct number of rows.    $range_rows = db_query_range("SELECT name FROM {system} ORDER BY name", 2, 3)->fetchAll();    $this->assertEqual(count($range_rows), 3, 'Range query work and return correct number of rows.');    // Test if return target data.    $raw_rows = db_query('SELECT name FROM {system} ORDER BY name')->fetchAll();    $raw_rows = array_slice($raw_rows, 2, 3);    $this->assertEqual($range_rows, $raw_rows, 'Range query work and return target data.');  }}/** * Temporary query tests. */class DatabaseTemporaryQueryTestCase extends DrupalWebTestCase {  public static function getInfo() {    return array(      'name' => 'Temporary query test',      'description' => 'Test the temporary query functionality.',      'group' => 'Database',    );  }  function setUp() {    parent::setUp('database_test');  }  /**   * Return the number of rows of a table.   */  function countTableRows($table_name) {    return db_select($table_name)->countQuery()->execute()->fetchField();  }  /**   * Confirm that temporary tables work and are limited to one request.   */  function testTemporaryQuery() {    $this->drupalGet('database_test/db_query_temporary');    $data = json_decode($this->drupalGetContent());    if ($data) {      $this->assertEqual($this->countTableRows("system"), $data->row_count, 'The temporary table contains the correct amount of rows.');      $this->assertFalse(db_table_exists($data->table_name), 'The temporary table is, indeed, temporary.');    }    else {      $this->fail("The creation of the temporary table failed.");    }    // Now try to run two db_query_temporary() in the same request.    $table_name_system = db_query_temporary('SELECT status FROM {system}', array());    $table_name_users = db_query_temporary('SELECT uid FROM {users}', array());    $this->assertEqual($this->countTableRows($table_name_system), $this->countTableRows("system"), 'A temporary table was created successfully in this request.');    $this->assertEqual($this->countTableRows($table_name_users), $this->countTableRows("users"), 'A second temporary table was created successfully in this request.');    // Check that leading whitespace and comments do not cause problems    // in the modified query.    $sql = "      -- Let's select some rows into a temporary table      SELECT name FROM {test}    ";    $table_name_test = db_query_temporary($sql, array());    $this->assertEqual($this->countTableRows($table_name_test), $this->countTableRows('test'), 'Leading white space and comments do not interfere with temporary table creation.');  }}/** * Test how the current database driver interprets the SQL syntax. * * In order to ensure consistent SQL handling throughout Drupal * across multiple kinds of database systems, we test that the * database system interprets SQL syntax in an expected fashion. */class DatabaseBasicSyntaxTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Basic SQL syntax tests',      'description' => 'Test SQL syntax interpretation.',      'group' => 'Database',    );  }  function setUp() {    parent::setUp('database_test');  }  /**   * Test for string concatenation.   */  function testBasicConcat() {    $result = db_query('SELECT CONCAT(:a1, CONCAT(:a2, CONCAT(:a3, CONCAT(:a4, :a5))))', array(      ':a1' => 'This',      ':a2' => ' ',      ':a3' => 'is',      ':a4' => ' a ',      ':a5' => 'test.',    ));    $this->assertIdentical($result->fetchField(), 'This is a test.', 'Basic CONCAT works.');  }  /**   * Test for string concatenation with field values.   */  function testFieldConcat() {    $result = db_query('SELECT CONCAT(:a1, CONCAT(name, CONCAT(:a2, CONCAT(age, :a3)))) FROM {test} WHERE age = :age', array(      ':a1' => 'The age of ',      ':a2' => ' is ',      ':a3' => '.',      ':age' => 25,    ));    $this->assertIdentical($result->fetchField(), 'The age of John is 25.', 'Field CONCAT works.');  }  /**   * Test escaping of LIKE wildcards.   */  function testLikeEscape() {    db_insert('test')      ->fields(array(        'name' => 'Ring_',      ))      ->execute();    // Match both "Ringo" and "Ring_".    $num_matches = db_select('test', 't')      ->condition('name', 'Ring_', 'LIKE')      ->countQuery()      ->execute()      ->fetchField();    $this->assertIdentical($num_matches, '2', 'Found 2 records.');    // Match only "Ring_" using a LIKE expression with no wildcards.    $num_matches = db_select('test', 't')      ->condition('name', db_like('Ring_'), 'LIKE')      ->countQuery()      ->execute()      ->fetchField();    $this->assertIdentical($num_matches, '1', 'Found 1 record.');  }  /**   * Test LIKE query containing a backslash.   */  function testLikeBackslash() {    db_insert('test')      ->fields(array('name'))      ->values(array(        'name' => 'abcde\f',      ))      ->values(array(        'name' => 'abc%\_',      ))      ->execute();    // Match both rows using a LIKE expression with two wildcards and a verbatim    // backslash.    $num_matches = db_select('test', 't')      ->condition('name', 'abc%\\\\_', 'LIKE')      ->countQuery()      ->execute()      ->fetchField();    $this->assertIdentical($num_matches, '2', 'Found 2 records.');    // Match only the former using a LIKE expression with no wildcards.    $num_matches = db_select('test', 't')      ->condition('name', db_like('abc%\_'), 'LIKE')      ->countQuery()      ->execute()      ->fetchField();    $this->assertIdentical($num_matches, '1', 'Found 1 record.');  }}/** * Test case sensitivity handling. */class DatabaseCaseSensitivityTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Case sensitivity',      'description' => 'Test handling case sensitive collation.',      'group' => 'Database',    );  }  /**   * Test BINARY collation in MySQL.   */  function testCaseSensitiveInsert() {    $num_records_before = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $john = db_insert('test')      ->fields(array(        'name' => 'john', // <- A record already exists with name 'John'.        'age' => 2,        'job' => 'Baby',      ))      ->execute();    $num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();    $this->assertIdentical($num_records_before + 1, (int) $num_records_after, 'Record inserts correctly.');    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'john'))->fetchField();    $this->assertIdentical($saved_age, '2', 'Can retrieve after inserting.');  }}/** * Test invalid data handling. */class DatabaseInvalidDataTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Invalid data',      'description' => 'Test handling of some invalid data.',      'group' => 'Database',    );  }  function setUp() {    parent::setUp('database_test');  }  /**   * Traditional SQL database systems abort inserts when invalid data is encountered.   */  function testInsertDuplicateData() {    // Try to insert multiple records where at least one has bad data.    try {      db_insert('test')        ->fields(array('name', 'age', 'job'))        ->values(array(          'name' => 'Elvis',          'age' => 63,          'job' => 'Singer',        ))->values(array(          'name' => 'John', // <-- Duplicate value on unique field.          'age' => 17,          'job' => 'Consultant',        ))        ->values(array(          'name' => 'Frank',          'age' => 75,          'job' => 'Singer',        ))        ->execute();      $this->fail('Insert succeedded when it should not have.');    }    catch (Exception $e) {      // Check if the first record was inserted.      $name = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 63))->fetchField();      if ($name == 'Elvis') {        if (!Database::getConnection()->supportsTransactions()) {          // This is an expected fail.          // Database engines that don't support transactions can leave partial          // inserts in place when an error occurs. This is the case for MySQL          // when running on a MyISAM table.          $this->pass("The whole transaction has not been rolled-back when a duplicate key insert occurs, this is expected because the database doesn't support transactions");        }        else {          $this->fail('The whole transaction is rolled back when a duplicate key insert occurs.');        }      }      else {        $this->pass('The whole transaction is rolled back when a duplicate key insert occurs.');      }      // Ensure the other values were not inserted.      $record = db_select('test')        ->fields('test', array('name', 'age'))        ->condition('age', array(17, 75), 'IN')        ->execute()->fetchObject();      $this->assertFalse($record, 'The rest of the insert aborted as expected.');    }  }}/** * Drupal-specific SQL syntax tests. */class DatabaseQueryTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Custom query syntax tests',      'description' => 'Test Drupal\'s extended prepared statement syntax..',      'group' => 'Database',    );  }  function setUp() {    parent::setUp('database_test');  }  /**   * Test that we can specify an array of values in the query by simply passing in an array.   */  function testArraySubstitution() {    $names = db_query('SELECT name FROM {test} WHERE age IN (:ages) ORDER BY age', array(':ages' => array(25, 26, 27)))->fetchAll();    $this->assertEqual(count($names), 3, 'Correct number of names returned');  }  /**   * Test SQL injection via database query array arguments.   */  public function testArrayArgumentsSQLInjection() {    // Attempt SQL injection and verify that it does not work.    $condition = array(      "1 ;INSERT INTO {test} (name) VALUES ('test12345678'); -- " => '',      '1' => '',    );    try {      db_query("SELECT * FROM {test} WHERE name = :name", array(':name' => $condition))->fetchObject();      $this->fail('SQL injection attempt via array arguments should result in a PDOException.');    }    catch (PDOException $e) {      $this->pass('SQL injection attempt via array arguments should result in a PDOException.');    }    // Test that the insert query that was used in the SQL injection attempt did    // not result in a row being inserted in the database.    $result = db_select('test')      ->condition('name', 'test12345678')      ->countQuery()      ->execute()      ->fetchField();    $this->assertFalse($result, 'SQL injection attempt did not result in a row being inserted in the database table.');  }}/** * Test transaction support, particularly nesting. * * We test nesting by having two transaction layers, an outer and inner. The * outer layer encapsulates the inner layer. Our transaction nesting abstraction * should allow the outer layer function to call any function it wants, * especially the inner layer that starts its own transaction, and be * confident that, when the function it calls returns, its own transaction * is still "alive." * * Call structure: *   transactionOuterLayer() *     Start transaction *     transactionInnerLayer() *       Start transaction (does nothing in database) *       [Maybe decide to roll back] *     Do more stuff *     Should still be in transaction A * */class DatabaseTransactionTestCase extends DatabaseTestCase {  public static function getInfo() {    return array(      'name' => 'Transaction tests',      'description' => 'Test the transaction abstraction system.',      'group' => 'Database',    );  }  /**   * Helper method for transaction unit test.   *   * This "outer layer" transaction starts and then encapsulates the   * "inner layer" transaction. This nesting is used to evaluate whether the   * database transaction API properly supports nesting. By "properly supports,"   * we mean the outer transaction continues to exist regardless of what   * functions are called and whether those functions start their own   * transactions.   *   * In contrast, a typical database would commit the outer transaction, start   * a new transaction for the inner layer, commit the inner layer transaction,   * and then be confused when the outer layer transaction tries to commit its   * transaction (which was already committed when the inner transaction   * started).   *   * @param $suffix   *   Suffix to add to field values to differentiate tests.   * @param $rollback   *   Whether or not to try rolling back the transaction when we're done.   * @param $ddl_statement   *   Whether to execute a DDL statement during the inner transaction.   */  protected function transactionOuterLayer($suffix, $rollback = FALSE, $ddl_statement = FALSE) {    $connection = Database::getConnection();    $depth = $connection->transactionDepth();    $txn = db_transaction();    // Insert a single row into the testing table.    db_insert('test')      ->fields(array(        'name' => 'David' . $suffix,        'age' => '24',      ))      ->execute();    $this->assertTrue($connection->inTransaction(), 'In transaction before calling nested transaction.');    // We're already in a transaction, but we call ->transactionInnerLayer    // to nest another transaction inside the current one.    $this->transactionInnerLayer($suffix, $rollback, $ddl_statement);    $this->assertTrue($connection->inTransaction(), 'In transaction after calling nested transaction.');    if ($rollback) {      // Roll back the transaction, if requested.      // This rollback should propagate to the last savepoint.      $txn->rollback();      $this->assertTrue(($connection->transactionDepth() == $depth), 'Transaction has rolled back to the last savepoint after calling rollback().');    }  }  /**   * Helper method for transaction unit tests. This "inner layer" transaction   * is either used alone or nested inside of the "outer layer" transaction.   *   * @param $suffix   *   Suffix to add to field values to differentiate tests.   * @param $rollback   *   Whether or not to try rolling back the transaction when we're done.   * @param $ddl_statement   *   Whether to execute a DDL statement during the transaction.   */  protected function transactionInnerLayer($suffix, $rollback = FALSE, $ddl_statement = FALSE) {    $connection = Database::getConnection();    $depth = $connection->transactionDepth();    // Start a transaction. If we're being called from ->transactionOuterLayer,    // then we're already in a transaction. Normally, that would make starting    // a transaction here dangerous, but the database API handles this problem    // for us by tracking the nesting and avoiding the danger.    $txn = db_transaction();    $depth2 = $connection->transactionDepth();    $this->assertTrue($depth < $depth2, 'Transaction depth is has increased with new transaction.');    // Insert a single row into the testing table.    db_insert('test')      ->fields(array(        'name' => 'Daniel' . $suffix,        'age' => '19',      ))      ->execute();    $this->assertTrue($connection->inTransaction(), 'In transaction inside nested transaction.');    if ($ddl_statement) {      $table = array(        'fields' => array(          'id' => array(            'type' => 'serial',            'unsigned' => TRUE,            'not null' => TRUE,          ),        ),        'primary key' => array('id'),      );      db_create_table('database_test_1', $table);      $this->assertTrue($connection->inTransaction(), 'In transaction inside nested transaction.');    }    if ($rollback) {      // Roll back the transaction, if requested.      // This rollback should propagate to the last savepoint.      $txn->rollback();      $this->assertTrue(($connection->transactionDepth() == $depth), 'Transaction has rolled back to the last savepoint after calling rollback().');    }  }  /**   * Test transaction rollback on a database that supports transactions.   *   * If the active connection does not support transactions, this test does nothing.   */  function testTransactionRollBackSupported() {    // This test won't work right if transactions are not supported.    if (!Database::getConnection()->supportsTransactions()) {      return;    }    try {      // Create two nested transactions. Roll back from the inner one.      $this->transactionOuterLayer('B', TRUE);      // Neither of the rows we inserted in the two transaction layers      // should be present in the tables post-rollback.      $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidB'))->fetchField();      $this->assertNotIdentical($saved_age, '24', 'Cannot retrieve DavidB row after commit.');      $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielB'))->fetchField();      $this->assertNotIdentical($saved_age, '19', 'Cannot retrieve DanielB row after commit.');    }    catch (Exception $e) {      $this->fail($e->getMessage());    }  }  /**   * Test transaction rollback on a database that does not support transactions.   *   * If the active driver supports transactions, this test does nothing.   */  function testTransactionRollBackNotSupported() {    // This test won't work right if transactions are supported.    if (Database::getConnection()->supportsTransactions()) {      return;    }    try {      // Create two nested transactions. Attempt to roll back from the inner one.      $this->transactionOuterLayer('B', TRUE);      // Because our current database claims to not support transactions,      // the inserted rows should be present despite the attempt to roll back.      $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidB'))->fetchField();      $this->assertIdentical($saved_age, '24', 'DavidB not rolled back, since transactions are not supported.');      $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielB'))->fetchField();      $this->assertIdentical($saved_age, '19', 'DanielB not rolled back, since transactions are not supported.');    }    catch (Exception $e) {      $this->fail($e->getMessage());    }  }  /**   * Test committed transaction.   *   * The behavior of this test should be identical for connections that support   * transactions and those that do not.   */  function testCommittedTransaction() {    try {      // Create two nested transactions. The changes should be committed.      $this->transactionOuterLayer('A');      // Because we committed, both of the inserted rows should be present.      $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidA'))->fetchField();      $this->assertIdentical($saved_age, '24', 'Can retrieve DavidA row after commit.');      $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielA'))->fetchField();      $this->assertIdentical($saved_age, '19', 'Can retrieve DanielA row after commit.');    }    catch (Exception $e) {      $this->fail($e->getMessage());    }  }  /**   * Test the compatibility of transactions with DDL statements.   */  function testTransactionWithDdlStatement() {    // First, test that a commit works normally, even with DDL statements.    $transaction = db_transaction();    $this->insertRow('row');    $this->executeDDLStatement();    unset($transaction);    $this->assertRowPresent('row');    // Even in different order.    $this->cleanUp();    $transaction = db_transaction();    $this->executeDDLStatement();    $this->insertRow('row');    unset($transaction);    $this->assertRowPresent('row');    // Even with stacking.    $this->cleanUp();    $transaction = db_transaction();    $transaction2 = db_transaction();    $this->executeDDLStatement();    unset($transaction2);    $transaction3 = db_transaction();    $this->insertRow('row');    unset($transaction3);    unset($transaction);    $this->assertRowPresent('row');    // A transaction after a DDL statement should still work the same.    $this->cleanUp();    $transaction = db_transaction();    $transaction2 = db_transaction();    $this->executeDDLStatement();    unset($transaction2);    $transaction3 = db_transaction();    $this->insertRow('row');    $transaction3->rollback();    unset($transaction3);    unset($transaction);    $this->assertRowAbsent('row');    // The behavior of a rollback depends on the type of database server.    if (Database::getConnection()->supportsTransactionalDDL()) {      // For database servers that support transactional DDL, a rollback      // of a transaction including DDL statements should be possible.      $this->cleanUp();      $transaction = db_transaction();      $this->insertRow('row');      $this->executeDDLStatement();      $transaction->rollback();      unset($transaction);      $this->assertRowAbsent('row');      // Including with stacking.      $this->cleanUp();      $transaction = db_transaction();      $transaction2 = db_transaction();      $this->executeDDLStatement();      unset($transaction2);      $transaction3 = db_transaction();      $this->insertRow('row');      unset($transaction3);      $transaction->rollback();      unset($transaction);      $this->assertRowAbsent('row');    }    else {      // For database servers that do not support transactional DDL,      // the DDL statement should commit the transaction stack.      $this->cleanUp();      $transaction = db_transaction();      $this->insertRow('row');      $this->executeDDLStatement();      // Rollback the outer transaction.      try {        $transaction->rollback();        unset($transaction);        // @TODO: an exception should be triggered here, but is not, because        // "ROLLBACK" fails silently in MySQL if there is no transaction active.        // $this->fail(t('Rolling back a transaction containing DDL should fail.'));      }      catch (DatabaseTransactionNoActiveException $e) {        $this->pass('Rolling back a transaction containing DDL should fail.');      }      $this->assertRowPresent('row');    }  }  /**   * Insert a single row into the testing table.   */  protected function insertRow($name) {    db_insert('test')      ->fields(array(        'name' => $name,      ))      ->execute();  }  /**   * Execute a DDL statement.   */  protected function executeDDLStatement() {    static $count = 0;    $table = array(      'fields' => array(        'id' => array(          'type' => 'serial',          'unsigned' => TRUE,          'not null' => TRUE,        ),      ),      'primary key' => array('id'),    );    db_create_table('database_test_' . ++$count, $table);  }  /**   * Start over for a new test.   */  protected function cleanUp() {    db_truncate('test')      ->execute();  }  /**   * Assert that a given row is present in the test table.   *   * @param $name   *   The name of the row.   * @param $message   *   The message to log for the assertion.   */  function assertRowPresent($name, $message = NULL) {    if (!isset($message)) {      $message = format_string('Row %name is present.', array('%name' => $name));    }    $present = (boolean) db_query('SELECT 1 FROM {test} WHERE name = :name', array(':name' => $name))->fetchField();    return $this->assertTrue($present, $message);  }  /**   * Assert that a given row is absent from the test table.   *   * @param $name   *   The name of the row.   * @param $message   *   The message to log for the assertion.   */  function assertRowAbsent($name, $message = NULL) {    if (!isset($message)) {      $message = format_string('Row %name is absent.', array('%name' => $name));    }    $present = (boolean) db_query('SELECT 1 FROM {test} WHERE name = :name', array(':name' => $name))->fetchField();    return $this->assertFalse($present, $message);  }  /**   * Test transaction stacking and commit / rollback.   */  function testTransactionStacking() {    // This test won't work right if transactions are not supported.    if (!Database::getConnection()->supportsTransactions()) {      return;    }    $database = Database::getConnection();    // Standard case: pop the inner transaction before the outer transaction.    $transaction = db_transaction();    $this->insertRow('outer');    $transaction2 = db_transaction();    $this->insertRow('inner');    // Pop the inner transaction.    unset($transaction2);    $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the inner transaction');    // Pop the outer transaction.    unset($transaction);    $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the outer transaction');    $this->assertRowPresent('outer');    $this->assertRowPresent('inner');    // Pop the transaction in a different order they have been pushed.    $this->cleanUp();    $transaction = db_transaction();    $this->insertRow('outer');    $transaction2 = db_transaction();    $this->insertRow('inner');    // Pop the outer transaction, nothing should happen.    unset($transaction);    $this->insertRow('inner-after-outer-commit');    $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the outer transaction');    // Pop the inner transaction, the whole transaction should commit.    unset($transaction2);    $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the inner transaction');    $this->assertRowPresent('outer');    $this->assertRowPresent('inner');    $this->assertRowPresent('inner-after-outer-commit');    // Rollback the inner transaction.    $this->cleanUp();    $transaction = db_transaction();    $this->insertRow('outer');    $transaction2 = db_transaction();    $this->insertRow('inner');    // Now rollback the inner transaction.    $transaction2->rollback();    unset($transaction2);    $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the outer transaction');    // Pop the outer transaction, it should commit.    $this->insertRow('outer-after-inner-rollback');    unset($transaction);    $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the inner transaction');    $this->assertRowPresent('outer');    $this->assertRowAbsent('inner');    $this->assertRowPresent('outer-after-inner-rollback');    // Rollback the inner transaction after committing the outer one.    $this->cleanUp();    $transaction = db_transaction();    $this->insertRow('outer');    $transaction2 = db_transaction();    $this->insertRow('inner');    // Pop the outer transaction, nothing should happen.    unset($transaction);    $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the outer transaction');    // Now rollback the inner transaction, it should rollback.    $transaction2->rollback();    unset($transaction2);    $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the inner transaction');    $this->assertRowPresent('outer');    $this->assertRowAbsent('inner');    // Rollback the outer transaction while the inner transaction is active.    // In that case, an exception will be triggered because we cannot    // ensure that the final result will have any meaning.    $this->cleanUp();    $transaction = db_transaction();    $this->insertRow('outer');    $transaction2 = db_transaction();    $this->insertRow('inner');    $transaction3 = db_transaction();    $this->insertRow('inner2');    // Rollback the outer transaction.    try {      $transaction->rollback();      unset($transaction);      $this->fail('Rolling back the outer transaction while the inner transaction is active resulted in an exception.');    }    catch (DatabaseTransactionOutOfOrderException $e) {      $this->pass('Rolling back the outer transaction while the inner transaction is active resulted in an exception.');    }    $this->assertFalse($database->inTransaction(), 'No more in a transaction after rolling back the outer transaction');    // Try to commit one inner transaction.    unset($transaction3);    $this->pass('Trying to commit an inner transaction resulted in an exception.');    // Try to rollback one inner transaction.    try {      $transaction->rollback();      unset($transaction2);      $this->fail('Trying to commit an inner transaction resulted in an exception.');    }    catch (DatabaseTransactionNoActiveException $e) {      $this->pass('Trying to commit an inner transaction resulted in an exception.');    }    $this->assertRowAbsent('outer');    $this->assertRowAbsent('inner');    $this->assertRowAbsent('inner2');  }}/** * Check the sequences API. */class DatabaseNextIdCase extends DrupalWebTestCase {  public static function getInfo() {    return array(      'name' => 'Sequences API',      'description' => 'Test the secondary sequences API.',      'group' => 'Database',    );  }  /**   * Test that the sequences API work.   */  function testDbNextId() {    $first = db_next_id();    $second = db_next_id();    // We can test for exact increase in here because we know there is no    // other process operating on these tables -- normally we could only    // expect $second > $first.    $this->assertEqual($first + 1, $second, 'The second call from a sequence provides a number increased by one.');    $result = db_next_id(1000);    $this->assertEqual($result, 1001, 'Sequence provides a larger number than the existing ID.');  }}/** * Tests the empty pseudo-statement class. */class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {  public static function getInfo() {    return array(      'name' => 'Empty statement',      'description' => 'Test the empty pseudo-statement class.',      'group' => 'Database',    );  }  /**   * Test that the empty result set behaves as empty.   */  function testEmpty() {    $result = new DatabaseStatementEmpty();    $this->assertTrue($result instanceof DatabaseStatementInterface, 'Class implements expected interface');    $this->assertNull($result->fetchObject(), 'Null result returned.');  }  /**   * Test that the empty result set iterates safely.   */  function testEmptyIteration() {    $result = new DatabaseStatementEmpty();    foreach ($result as $record) {      $this->fail('Iterating empty result set should not iterate.');      return;    }    $this->pass('Iterating empty result set skipped iteration.');  }  /**   * Test that the empty result set mass-fetches in an expected way.   */  function testEmptyFetchAll() {    $result = new DatabaseStatementEmpty();    $this->assertEqual($result->fetchAll(), array(), 'Empty array returned from empty result set.');  }}/** * Tests management of database connections. */class ConnectionUnitTest extends DrupalUnitTestCase {  protected $key;  protected $target;  protected $monitor;  protected $originalCount;  public static function getInfo() {    return array(      'name' => 'Connection unit tests',      'description' => 'Tests management of database connections.',      'group' => 'Database',    );  }  function setUp() {    parent::setUp();    $this->key = 'default';    $this->originalTarget = 'default';    $this->target = 'DatabaseConnectionUnitTest';    // Determine whether the database driver is MySQL. If it is not, the test    // methods will not be executed.    // @todo Make this test driver-agnostic, or find a proper way to skip it.    // @see http://drupal.org/node/1273478    $connection_info = Database::getConnectionInfo('default');    $this->skipTest = (bool) $connection_info['default']['driver'] != 'mysql';    if ($this->skipTest) {      // Insert an assertion to prevent Simpletest from interpreting the test      // as failure.      $this->pass('This test is only compatible with MySQL.');    }    // Create an additional connection to monitor the connections being opened    // and closed in this test.    // @see TestBase::changeDatabasePrefix()    $connection_info = Database::getConnectionInfo('default');    Database::addConnectionInfo('default', 'monitor', $connection_info['default']);    global $databases;    $databases['default']['monitor'] = $connection_info['default'];    $this->monitor = Database::getConnection('monitor');  }  /**   * Adds a new database connection info to Database.   */  protected function addConnection() {    // Add a new target to the connection, by cloning the current connection.    $connection_info = Database::getConnectionInfo($this->key);    Database::addConnectionInfo($this->key, $this->target, $connection_info[$this->originalTarget]);    // Verify that the new target exists.    $info = Database::getConnectionInfo($this->key);    // Note: Custom assertion message to not expose database credentials.    $this->assertIdentical($info[$this->target], $connection_info[$this->key], 'New connection info found.');  }  /**   * Returns the connection ID of the current test connection.   *   * @return integer   */  protected function getConnectionID() {    return (int) Database::getConnection($this->target, $this->key)->query('SELECT CONNECTION_ID()')->fetchField();  }  /**   * Asserts that a connection ID exists.   *   * @param integer $id   *   The connection ID to verify.   */  protected function assertConnection($id) {    $list = $this->monitor->query('SHOW PROCESSLIST')->fetchAllKeyed(0, 0);    return $this->assertTrue(isset($list[$id]), format_string('Connection ID @id found.', array('@id' => $id)));  }  /**   * Asserts that a connection ID does not exist.   *   * @param integer $id   *   The connection ID to verify.   */  protected function assertNoConnection($id) {    $list = $this->monitor->query('SHOW PROCESSLIST')->fetchAllKeyed(0, 0);    return $this->assertFalse(isset($list[$id]), format_string('Connection ID @id not found.', array('@id' => $id)));  }  /**   * Tests Database::closeConnection() without query.   *   * @todo getConnectionID() executes a query.   */  function testOpenClose() {    if ($this->skipTest) {      return;    }    // Add and open a new connection.    $this->addConnection();    $id = $this->getConnectionID();    Database::getConnection($this->target, $this->key);    // Verify that there is a new connection.    $this->assertConnection($id);    // Close the connection.    Database::closeConnection($this->target, $this->key);    // Wait 20ms to give the database engine sufficient time to react.    usleep(20000);    // Verify that we are back to the original connection count.    $this->assertNoConnection($id);  }  /**   * Tests Database::closeConnection() with a query.   */  function testOpenQueryClose() {    if ($this->skipTest) {      return;    }    // Add and open a new connection.    $this->addConnection();    $id = $this->getConnectionID();    Database::getConnection($this->target, $this->key);    // Verify that there is a new connection.    $this->assertConnection($id);    // Execute a query.    Database::getConnection($this->target, $this->key)->query('SHOW TABLES');    // Close the connection.    Database::closeConnection($this->target, $this->key);    // Wait 20ms to give the database engine sufficient time to react.    usleep(20000);    // Verify that we are back to the original connection count.    $this->assertNoConnection($id);  }  /**   * Tests Database::closeConnection() with a query and custom prefetch method.   */  function testOpenQueryPrefetchClose() {    if ($this->skipTest) {      return;    }    // Add and open a new connection.    $this->addConnection();    $id = $this->getConnectionID();    Database::getConnection($this->target, $this->key);    // Verify that there is a new connection.    $this->assertConnection($id);    // Execute a query.    Database::getConnection($this->target, $this->key)->query('SHOW TABLES')->fetchCol();    // Close the connection.    Database::closeConnection($this->target, $this->key);    // Wait 20ms to give the database engine sufficient time to react.    usleep(20000);    // Verify that we are back to the original connection count.    $this->assertNoConnection($id);  }  /**   * Tests Database::closeConnection() with a select query.   */  function testOpenSelectQueryClose() {    if ($this->skipTest) {      return;    }    // Add and open a new connection.    $this->addConnection();    $id = $this->getConnectionID();    Database::getConnection($this->target, $this->key);    // Verify that there is a new connection.    $this->assertConnection($id);    // Create a table.    $name = 'foo';    Database::getConnection($this->target, $this->key)->schema()->createTable($name, array(      'fields' => array(        'name' => array(          'type' => 'varchar',          'length' => 255,        ),      ),    ));    // Execute a query.    Database::getConnection($this->target, $this->key)->select('foo', 'f')      ->fields('f', array('name'))      ->execute()      ->fetchAll();    // Drop the table.    Database::getConnection($this->target, $this->key)->schema()->dropTable($name);    // Close the connection.    Database::closeConnection($this->target, $this->key);    // Wait 20ms to give the database engine sufficient time to react.    usleep(20000);    // Verify that we are back to the original connection count.    $this->assertNoConnection($id);  }}
 |