ExportSql.class.php 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Set of functions used to build SQL dumps of tables
  5. *
  6. * @package PhpMyAdmin-Export
  7. * @subpackage SQL
  8. */
  9. if (! defined('PHPMYADMIN')) {
  10. exit;
  11. }
  12. /* Get the export interface */
  13. require_once 'libraries/plugins/ExportPlugin.class.php';
  14. /**
  15. * Handles the export for the SQL class
  16. *
  17. * @package PhpMyAdmin-Export
  18. * @subpackage SQL
  19. */
  20. class ExportSql extends ExportPlugin
  21. {
  22. /**
  23. * Constructor
  24. */
  25. public function __construct()
  26. {
  27. $this->setProperties();
  28. // Avoids undefined variables, use NULL so isset() returns false
  29. if (! isset($GLOBALS['sql_backquotes'])) {
  30. $GLOBALS['sql_backquotes'] = null;
  31. }
  32. }
  33. /**
  34. * Sets the export SQL properties
  35. *
  36. * @return void
  37. */
  38. protected function setProperties()
  39. {
  40. global $plugin_param;
  41. $hide_sql = false;
  42. $hide_structure = false;
  43. if ($plugin_param['export_type'] == 'table'
  44. && ! $plugin_param['single_table']
  45. ) {
  46. $hide_structure = true;
  47. $hide_sql = true;
  48. }
  49. if (! $hide_sql) {
  50. $props = 'libraries/properties/';
  51. include_once "$props/plugins/ExportPluginProperties.class.php";
  52. include_once "$props/options/groups/OptionsPropertyRootGroup.class.php";
  53. include_once "$props/options/groups/OptionsPropertyMainGroup.class.php";
  54. include_once "$props/options/groups/OptionsPropertySubgroup.class.php";
  55. include_once "$props/options/items/BoolPropertyItem.class.php";
  56. include_once "$props/options/items/MessageOnlyPropertyItem.class.php";
  57. include_once "$props/options/items/RadioPropertyItem.class.php";
  58. include_once "$props/options/items/SelectPropertyItem.class.php";
  59. include_once "$props/options/items/TextPropertyItem.class.php";
  60. include_once "$props/options/items/NumberPropertyItem.class.php";
  61. $exportPluginProperties = new ExportPluginProperties();
  62. $exportPluginProperties->setText('SQL');
  63. $exportPluginProperties->setExtension('sql');
  64. $exportPluginProperties->setMimeType('text/x-sql');
  65. $exportPluginProperties->setOptionsText(__('Options'));
  66. // create the root group that will be the options field for
  67. // $exportPluginProperties
  68. // this will be shown as "Format specific options"
  69. $exportSpecificOptions = new OptionsPropertyRootGroup();
  70. $exportSpecificOptions->setName("Format Specific Options");
  71. // general options main group
  72. $generalOptions = new OptionsPropertyMainGroup();
  73. $generalOptions->setName("general_opts");
  74. // comments
  75. $subgroup = new OptionsPropertySubgroup();
  76. $subgroup->setName("include_comments");
  77. $leaf = new BoolPropertyItem();
  78. $leaf->setName('include_comments');
  79. $leaf->setText(
  80. __(
  81. 'Display comments <i>(includes info such as export'
  82. . ' timestamp, PHP version, and server version)</i>'
  83. )
  84. );
  85. $subgroup->setSubgroupHeader($leaf);
  86. $leaf = new TextPropertyItem();
  87. $leaf->setName('header_comment');
  88. $leaf->setText(
  89. __('Additional custom header comment (\n splits lines):')
  90. );
  91. $subgroup->addProperty($leaf);
  92. $leaf = new BoolPropertyItem();
  93. $leaf->setName('dates');
  94. $leaf->setText(
  95. __(
  96. 'Include a timestamp of when databases were created, last'
  97. . ' updated, and last checked'
  98. )
  99. );
  100. $subgroup->addProperty($leaf);
  101. if (! empty($GLOBALS['cfgRelation']['relation'])) {
  102. $leaf = new BoolPropertyItem();
  103. $leaf->setName('relation');
  104. $leaf->setText(__('Display foreign key relationships'));
  105. $subgroup->addProperty($leaf);
  106. }
  107. if (! empty($GLOBALS['cfgRelation']['mimework'])) {
  108. $leaf = new BoolPropertyItem();
  109. $leaf->setName('mime');
  110. $leaf->setText(__('Display MIME types'));
  111. $subgroup->addProperty($leaf);
  112. }
  113. $generalOptions->addProperty($subgroup);
  114. // enclose in a transaction
  115. $leaf = new BoolPropertyItem();
  116. $leaf->setName("use_transaction");
  117. $leaf->setText(__('Enclose export in a transaction'));
  118. $leaf->setDoc(
  119. array(
  120. 'programs',
  121. 'mysqldump',
  122. 'option_mysqldump_single-transaction'
  123. )
  124. );
  125. $generalOptions->addProperty($leaf);
  126. // disable foreign key checks
  127. $leaf = new BoolPropertyItem();
  128. $leaf->setName("disable_fk");
  129. $leaf->setText(__('Disable foreign key checks'));
  130. $leaf->setDoc(
  131. array(
  132. 'manual_MySQL_Database_Administration',
  133. 'server-system-variables',
  134. 'sysvar_foreign_key_checks'
  135. )
  136. );
  137. $generalOptions->addProperty($leaf);
  138. // export views as tables
  139. $leaf = new BoolPropertyItem();
  140. $leaf->setName("views_as_tables");
  141. $leaf->setText(__('Export views as tables'));
  142. $generalOptions->addProperty($leaf);
  143. // compatibility maximization
  144. $compats = $GLOBALS['dbi']->getCompatibilities();
  145. if (count($compats) > 0) {
  146. $values = array();
  147. foreach ($compats as $val) {
  148. $values[$val] = $val;
  149. }
  150. $leaf = new SelectPropertyItem();
  151. $leaf->setName("compatibility");
  152. $leaf->setText(
  153. __(
  154. 'Database system or older MySQL server to maximize output'
  155. . ' compatibility with:'
  156. )
  157. );
  158. $leaf->setValues($values);
  159. $leaf->setDoc(
  160. array(
  161. 'manual_MySQL_Database_Administration',
  162. 'Server_SQL_mode'
  163. )
  164. );
  165. $generalOptions->addProperty($leaf);
  166. unset($values);
  167. }
  168. // server export options
  169. if ($plugin_param['export_type'] == 'server') {
  170. $leaf = new BoolPropertyItem();
  171. $leaf->setName("drop_database");
  172. $leaf->setText(
  173. sprintf(__('Add %s statement'), '<code>DROP DATABASE</code>')
  174. );
  175. $generalOptions->addProperty($leaf);
  176. }
  177. // what to dump (structure/data/both)
  178. $subgroup = new OptionsPropertySubgroup();
  179. $subgroup->setName("dump_table");
  180. $subgroup->setText("Dump table");
  181. $leaf = new RadioPropertyItem();
  182. $leaf->setName('structure_or_data');
  183. $leaf->setValues(
  184. array(
  185. 'structure' => __('structure'),
  186. 'data' => __('data'),
  187. 'structure_and_data' => __('structure and data')
  188. )
  189. );
  190. $subgroup->setSubgroupHeader($leaf);
  191. $generalOptions->addProperty($subgroup);
  192. // add the main group to the root group
  193. $exportSpecificOptions->addProperty($generalOptions);
  194. // structure options main group
  195. if (! $hide_structure) {
  196. $structureOptions = new OptionsPropertyMainGroup();
  197. $structureOptions->setName("structure");
  198. $structureOptions->setText(__('Object creation options'));
  199. $structureOptions->setForce('data');
  200. // begin SQL Statements
  201. $subgroup = new OptionsPropertySubgroup();
  202. $leaf = new MessageOnlyPropertyItem();
  203. $leaf->setName('add_statements');
  204. $leaf->setText(__('Add statements:'));
  205. $subgroup->setSubgroupHeader($leaf);
  206. if ($plugin_param['export_type'] != 'table') {
  207. $leaf = new BoolPropertyItem();
  208. $leaf->setName('create_database');
  209. $create_clause = '<code>CREATE DATABASE / USE</code>';
  210. $leaf->setText(sprintf(__('Add %s statement'), $create_clause));
  211. $subgroup->addProperty($leaf);
  212. }
  213. if ($plugin_param['export_type'] == 'table') {
  214. if (PMA_Table::isView($GLOBALS['db'], $GLOBALS['table'])) {
  215. $drop_clause = '<code>DROP VIEW</code>';
  216. } else {
  217. $drop_clause = '<code>DROP TABLE</code>';
  218. }
  219. } else {
  220. if (PMA_DRIZZLE) {
  221. $drop_clause = '<code>DROP TABLE</code>';
  222. } else {
  223. $drop_clause = '<code>DROP TABLE / VIEW / PROCEDURE'
  224. . ' / FUNCTION</code>';
  225. if (PMA_MYSQL_INT_VERSION > 50100) {
  226. $drop_clause .= '<code> / EVENT</code>';
  227. }
  228. }
  229. }
  230. $drop_clause .= '<code> / TRIGGER</code>';
  231. $leaf = new BoolPropertyItem();
  232. $leaf->setName('drop_table');
  233. $leaf->setText(sprintf(__('Add %s statement'), $drop_clause));
  234. $subgroup->addProperty($leaf);
  235. // Add table structure option
  236. $leaf = new BoolPropertyItem();
  237. $leaf->setName('create_table');
  238. $leaf->setText(
  239. sprintf(__('Add %s statement'), '<code>CREATE TABLE</code>')
  240. );
  241. $subgroup->addProperty($leaf);
  242. // Add view option
  243. $leaf = new BoolPropertyItem();
  244. $leaf->setName('create_view');
  245. $leaf->setText(
  246. sprintf(__('Add %s statement'), '<code>CREATE VIEW</code>')
  247. );
  248. $subgroup->addProperty($leaf);
  249. // Drizzle doesn't support procedures and functions
  250. if (! PMA_DRIZZLE) {
  251. $leaf = new BoolPropertyItem();
  252. $leaf->setName('procedure_function');
  253. $leaf->setText(
  254. sprintf(
  255. __('Add %s statement'),
  256. '<code>CREATE PROCEDURE / FUNCTION'
  257. . (PMA_MYSQL_INT_VERSION > 50100
  258. ? ' / EVENT</code>' : '</code>')
  259. )
  260. );
  261. $subgroup->addProperty($leaf);
  262. }
  263. // Add triggers option
  264. $leaf = new BoolPropertyItem();
  265. $leaf->setName('create_trigger');
  266. $leaf->setText(
  267. sprintf(__('Add %s statement'), '<code>CREATE TRIGGER</code>')
  268. );
  269. $subgroup->addProperty($leaf);
  270. // begin CREATE TABLE statements
  271. $subgroup_create_table = new OptionsPropertySubgroup();
  272. $leaf = new BoolPropertyItem();
  273. $leaf->setName('create_table_statements');
  274. $leaf->setText(__('<code>CREATE TABLE</code> options:'));
  275. $subgroup_create_table->setSubgroupHeader($leaf);
  276. $leaf = new BoolPropertyItem();
  277. $leaf->setName('if_not_exists');
  278. $leaf->setText('<code>IF NOT EXISTS</code>');
  279. $subgroup_create_table->addProperty($leaf);
  280. $leaf = new BoolPropertyItem();
  281. $leaf->setName('auto_increment');
  282. $leaf->setText('<code>AUTO_INCREMENT</code>');
  283. $subgroup_create_table->addProperty($leaf);
  284. $subgroup->addProperty($subgroup_create_table);
  285. $structureOptions->addProperty($subgroup);
  286. $leaf = new BoolPropertyItem();
  287. $leaf->setName("backquotes");
  288. $leaf->setText(
  289. __(
  290. 'Enclose table and column names with backquotes '
  291. . '<i>(Protects column and table names formed with'
  292. . ' special characters or keywords)</i>'
  293. )
  294. );
  295. $structureOptions->addProperty($leaf);
  296. // add the main group to the root group
  297. $exportSpecificOptions->addProperty($structureOptions);
  298. }
  299. // begin Data options
  300. $dataOptions = new OptionsPropertyMainGroup();
  301. $dataOptions->setName("data");
  302. $dataOptions->setText(__('Data creation options'));
  303. $dataOptions->setForce('structure');
  304. $leaf = new BoolPropertyItem();
  305. $leaf->setName("truncate");
  306. $leaf->setText(__('Truncate table before insert'));
  307. $dataOptions->addProperty($leaf);
  308. // begin SQL Statements
  309. $subgroup = new OptionsPropertySubgroup();
  310. $leaf = new MessageOnlyPropertyItem();
  311. $leaf->setText(__('Instead of <code>INSERT</code> statements, use:'));
  312. $subgroup->setSubgroupHeader($leaf);
  313. // Not supported in Drizzle
  314. if (! PMA_DRIZZLE) {
  315. $leaf = new BoolPropertyItem();
  316. $leaf->setName("delayed");
  317. $leaf->setText(__('<code>INSERT DELAYED</code> statements'));
  318. $leaf->setDoc(
  319. array(
  320. 'manual_MySQL_Database_Administration',
  321. 'insert_delayed'
  322. )
  323. );
  324. $subgroup->addProperty($leaf);
  325. }
  326. $leaf = new BoolPropertyItem();
  327. $leaf->setName("ignore");
  328. $leaf->setText(__('<code>INSERT IGNORE</code> statements'));
  329. $leaf->setDoc(
  330. array(
  331. 'manual_MySQL_Database_Administration',
  332. 'insert'
  333. )
  334. );
  335. $subgroup->addProperty($leaf);
  336. $dataOptions->addProperty($subgroup);
  337. // Function to use when dumping dat
  338. $leaf = new SelectPropertyItem();
  339. $leaf->setName("type");
  340. $leaf->setText(__('Function to use when dumping data:'));
  341. $leaf->setValues(
  342. array(
  343. 'INSERT' => 'INSERT',
  344. 'UPDATE' => 'UPDATE',
  345. 'REPLACE' => 'REPLACE'
  346. )
  347. );
  348. $dataOptions->addProperty($leaf);
  349. /* Syntax to use when inserting data */
  350. $subgroup = new OptionsPropertySubgroup();
  351. $leaf = new MessageOnlyPropertyItem();
  352. $leaf->setText(__('Syntax to use when inserting data:'));
  353. $subgroup->setSubgroupHeader($leaf);
  354. $leaf = new RadioPropertyItem();
  355. $leaf->setName("insert_syntax");
  356. $leaf->setText(__('<code>INSERT IGNORE</code> statements'));
  357. $leaf->setValues(
  358. array(
  359. 'complete' => __(
  360. 'include column names in every <code>INSERT</code> statement'
  361. . ' <br /> &nbsp; &nbsp; &nbsp; Example: <code>INSERT INTO'
  362. . ' tbl_name (col_A,col_B,col_C) VALUES (1,2,3)</code>'
  363. ),
  364. 'extended' => __(
  365. 'insert multiple rows in every <code>INSERT</code> statement'
  366. . '<br /> &nbsp; &nbsp; &nbsp; Example: <code>INSERT INTO'
  367. . ' tbl_name VALUES (1,2,3), (4,5,6), (7,8,9)</code>'
  368. ),
  369. 'both' => __(
  370. 'both of the above<br /> &nbsp; &nbsp; &nbsp; Example:'
  371. . ' <code>INSERT INTO tbl_name (col_A,col_B) VALUES (1,2,3),'
  372. . ' (4,5,6), (7,8,9)</code>'
  373. ),
  374. 'none' => __(
  375. 'neither of the above<br /> &nbsp; &nbsp; &nbsp; Example:'
  376. . ' <code>INSERT INTO tbl_name VALUES (1,2,3)</code>'
  377. )
  378. )
  379. );
  380. $subgroup->addProperty($leaf);
  381. $dataOptions->addProperty($subgroup);
  382. // Max length of query
  383. $leaf = new NumberPropertyItem();
  384. $leaf->setName("max_query_size");
  385. $leaf->setText(__('Maximal length of created query'));
  386. $dataOptions->addProperty($leaf);
  387. // Dump binary columns in hexadecimal
  388. $leaf = new BoolPropertyItem();
  389. $leaf->setName("hex_for_binary");
  390. $leaf->setText(
  391. __(
  392. 'Dump binary columns in hexadecimal notation'
  393. . ' <i>(for example, "abc" becomes 0x616263)</i>'
  394. )
  395. );
  396. $dataOptions->addProperty($leaf);
  397. // Drizzle works only with UTC timezone
  398. if (! PMA_DRIZZLE) {
  399. // Dump time in UTC
  400. $leaf = new BoolPropertyItem();
  401. $leaf->setName("utc_time");
  402. $leaf->setText(
  403. __(
  404. 'Dump TIMESTAMP columns in UTC <i>(enables TIMESTAMP columns'
  405. . ' to be dumped and reloaded between servers in different'
  406. . ' time zones)</i>'
  407. )
  408. );
  409. $dataOptions->addProperty($leaf);
  410. }
  411. // add the main group to the root group
  412. $exportSpecificOptions->addProperty($dataOptions);
  413. // set the options for the export plugin property item
  414. $exportPluginProperties->setOptions($exportSpecificOptions);
  415. $this->properties = $exportPluginProperties;
  416. }
  417. }
  418. /**
  419. * This method is called when any PluginManager to which the observer
  420. * is attached calls PluginManager::notify()
  421. *
  422. * @param SplSubject $subject The PluginManager notifying the observer
  423. * of an update.
  424. *
  425. * @return void
  426. */
  427. public function update (SplSubject $subject)
  428. {
  429. }
  430. /**
  431. * Exports routines (procedures and functions)
  432. *
  433. * @param string $db Database
  434. *
  435. * @return bool Whether it succeeded
  436. */
  437. public function exportRoutines($db)
  438. {
  439. global $crlf;
  440. $text = '';
  441. $delimiter = '$$';
  442. $procedure_names = $GLOBALS['dbi']
  443. ->getProceduresOrFunctions($db, 'PROCEDURE');
  444. $function_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'FUNCTION');
  445. if ($procedure_names || $function_names) {
  446. $text .= $crlf
  447. . 'DELIMITER ' . $delimiter . $crlf;
  448. }
  449. if ($procedure_names) {
  450. $text .=
  451. $this->_exportComment()
  452. . $this->_exportComment(__('Procedures'))
  453. . $this->_exportComment();
  454. foreach ($procedure_names as $procedure_name) {
  455. if (! empty($GLOBALS['sql_drop_table'])) {
  456. $text .= 'DROP PROCEDURE IF EXISTS '
  457. . PMA_Util::backquote($procedure_name)
  458. . $delimiter . $crlf;
  459. }
  460. $text .= $GLOBALS['dbi']
  461. ->getDefinition($db, 'PROCEDURE', $procedure_name)
  462. . $delimiter . $crlf . $crlf;
  463. }
  464. }
  465. if ($function_names) {
  466. $text .=
  467. $this->_exportComment()
  468. . $this->_exportComment(__('Functions'))
  469. . $this->_exportComment();
  470. foreach ($function_names as $function_name) {
  471. if (! empty($GLOBALS['sql_drop_table'])) {
  472. $text .= 'DROP FUNCTION IF EXISTS '
  473. . PMA_Util::backquote($function_name)
  474. . $delimiter . $crlf;
  475. }
  476. $text .= $GLOBALS['dbi']
  477. ->getDefinition($db, 'FUNCTION', $function_name)
  478. . $delimiter . $crlf . $crlf;
  479. }
  480. }
  481. if ($procedure_names || $function_names) {
  482. $text .= 'DELIMITER ;' . $crlf;
  483. }
  484. if (! empty($text)) {
  485. return PMA_exportOutputHandler($text);
  486. } else {
  487. return false;
  488. }
  489. }
  490. /**
  491. * Possibly outputs comment
  492. *
  493. * @param string $text Text of comment
  494. *
  495. * @return string The formatted comment
  496. */
  497. private function _exportComment($text = '')
  498. {
  499. if (isset($GLOBALS['sql_include_comments'])
  500. && $GLOBALS['sql_include_comments']
  501. ) {
  502. // see http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html
  503. return '--' . (empty($text) ? '' : ' ') . $text . $GLOBALS['crlf'];
  504. } else {
  505. return '';
  506. }
  507. }
  508. /**
  509. * Possibly outputs CRLF
  510. *
  511. * @return string $crlf or nothing
  512. */
  513. private function _possibleCRLF()
  514. {
  515. if (isset($GLOBALS['sql_include_comments'])
  516. && $GLOBALS['sql_include_comments']
  517. ) {
  518. return $GLOBALS['crlf'];
  519. } else {
  520. return '';
  521. }
  522. }
  523. /**
  524. * Outputs export footer
  525. *
  526. * @return bool Whether it succeeded
  527. */
  528. public function exportFooter()
  529. {
  530. global $crlf, $mysql_charset_map;
  531. $foot = '';
  532. if (isset($GLOBALS['sql_disable_fk'])) {
  533. $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . $crlf;
  534. }
  535. if (isset($GLOBALS['sql_use_transaction'])) {
  536. $foot .= 'COMMIT;' . $crlf;
  537. }
  538. // restore connection settings
  539. $charset_of_file = isset($GLOBALS['charset_of_file'])
  540. ? $GLOBALS['charset_of_file'] : '';
  541. if (! empty($GLOBALS['asfile'])
  542. && isset($mysql_charset_map[$charset_of_file])
  543. && ! PMA_DRIZZLE
  544. ) {
  545. $foot .= $crlf
  546. . '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;'
  547. . $crlf
  548. . '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;'
  549. . $crlf
  550. . '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;'
  551. . $crlf;
  552. }
  553. /* Restore timezone */
  554. if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) {
  555. $GLOBALS['dbi']->query('SET time_zone = "' . $GLOBALS['old_tz'] . '"');
  556. }
  557. return PMA_exportOutputHandler($foot);
  558. }
  559. /**
  560. * Outputs export header. It is the first method to be called, so all
  561. * the required variables are initialized here.
  562. *
  563. * @return bool Whether it succeeded
  564. */
  565. public function exportHeader()
  566. {
  567. global $crlf, $cfg;
  568. global $mysql_charset_map;
  569. if (isset($GLOBALS['sql_compatibility'])) {
  570. $tmp_compat = $GLOBALS['sql_compatibility'];
  571. if ($tmp_compat == 'NONE') {
  572. $tmp_compat = '';
  573. }
  574. $GLOBALS['dbi']->tryQuery('SET SQL_MODE="' . $tmp_compat . '"');
  575. unset($tmp_compat);
  576. }
  577. $head = $this->_exportComment('phpMyAdmin SQL Dump')
  578. . $this->_exportComment('version ' . PMA_VERSION)
  579. . $this->_exportComment('http://www.phpmyadmin.net')
  580. . $this->_exportComment();
  581. $host_string = __('Host:') . ' ' . $cfg['Server']['host'];
  582. if (! empty($cfg['Server']['port'])) {
  583. $host_string .= ':' . $cfg['Server']['port'];
  584. }
  585. $head .= $this->_exportComment($host_string);
  586. $head .=
  587. $this->_exportComment(
  588. __('Generation Time:') . ' '
  589. . PMA_Util::localisedDate()
  590. )
  591. . $this->_exportComment(
  592. __('Server version:') . ' ' . PMA_MYSQL_STR_VERSION
  593. )
  594. . $this->_exportComment(__('PHP Version:') . ' ' . phpversion())
  595. . $this->_possibleCRLF();
  596. if (isset($GLOBALS['sql_header_comment'])
  597. && ! empty($GLOBALS['sql_header_comment'])
  598. ) {
  599. // '\n' is not a newline (like "\n" would be), it's the characters
  600. // backslash and n, as explained on the export interface
  601. $lines = explode('\n', $GLOBALS['sql_header_comment']);
  602. $head .= $this->_exportComment();
  603. foreach ($lines as $one_line) {
  604. $head .= $this->_exportComment($one_line);
  605. }
  606. $head .= $this->_exportComment();
  607. }
  608. if (isset($GLOBALS['sql_disable_fk'])) {
  609. $head .= 'SET FOREIGN_KEY_CHECKS=0;' . $crlf;
  610. }
  611. // We want exported AUTO_INCREMENT columns to have still same value,
  612. // do this only for recent MySQL exports
  613. if ((! isset($GLOBALS['sql_compatibility'])
  614. || $GLOBALS['sql_compatibility'] == 'NONE')
  615. && ! PMA_DRIZZLE
  616. ) {
  617. $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf;
  618. }
  619. if (isset($GLOBALS['sql_use_transaction'])) {
  620. $head .= 'SET AUTOCOMMIT = 0;' . $crlf
  621. . 'START TRANSACTION;' . $crlf;
  622. }
  623. /* Change timezone if we should export timestamps in UTC */
  624. if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) {
  625. $head .= 'SET time_zone = "+00:00";' . $crlf;
  626. $GLOBALS['old_tz'] = $GLOBALS['dbi']
  627. ->fetchValue('SELECT @@session.time_zone');
  628. $GLOBALS['dbi']->query('SET time_zone = "+00:00"');
  629. }
  630. $head .= $this->_possibleCRLF();
  631. if (! empty($GLOBALS['asfile']) && ! PMA_DRIZZLE) {
  632. // we are saving as file, therefore we provide charset information
  633. // so that a utility like the mysql client can interpret
  634. // the file correctly
  635. if (isset($GLOBALS['charset_of_file'])
  636. && isset($mysql_charset_map[$GLOBALS['charset_of_file']])
  637. ) {
  638. // we got a charset from the export dialog
  639. $set_names = $mysql_charset_map[$GLOBALS['charset_of_file']];
  640. } else {
  641. // by default we use the connection charset
  642. $set_names = $mysql_charset_map['utf-8'];
  643. }
  644. $head .= $crlf
  645. . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT='
  646. . '@@CHARACTER_SET_CLIENT */;' . $crlf
  647. . '/*!40101 SET @OLD_CHARACTER_SET_RESULTS='
  648. . '@@CHARACTER_SET_RESULTS */;' . $crlf
  649. . '/*!40101 SET @OLD_COLLATION_CONNECTION='
  650. . '@@COLLATION_CONNECTION */;' . $crlf
  651. . '/*!40101 SET NAMES ' . $set_names . ' */;' . $crlf . $crlf;
  652. }
  653. return PMA_exportOutputHandler($head);
  654. }
  655. /**
  656. * Outputs CREATE DATABASE statement
  657. *
  658. * @param string $db Database name
  659. *
  660. * @return bool Whether it succeeded
  661. */
  662. public function exportDBCreate($db)
  663. {
  664. global $crlf;
  665. if (isset($GLOBALS['sql_compatibility'])) {
  666. $compat = $GLOBALS['sql_compatibility'];
  667. } else {
  668. $compat = 'NONE';
  669. }
  670. if (isset($GLOBALS['sql_drop_database'])) {
  671. if (! PMA_exportOutputHandler(
  672. 'DROP DATABASE '
  673. . (isset($GLOBALS['sql_backquotes'])
  674. ? PMA_Util::backquoteCompat($db, $compat) : $db)
  675. . ';' . $crlf
  676. )) {
  677. return false;
  678. }
  679. }
  680. if (isset($GLOBALS['sql_create_database'])) {
  681. $create_query = 'CREATE DATABASE IF NOT EXISTS '
  682. . (isset($GLOBALS['sql_backquotes'])
  683. ? PMA_Util::backquoteCompat($db, $compat) : $db);
  684. $collation = PMA_getDbCollation($db);
  685. if (PMA_DRIZZLE) {
  686. $create_query .= ' COLLATE ' . $collation;
  687. } else {
  688. if (strpos($collation, '_')) {
  689. $create_query .= ' DEFAULT CHARACTER SET '
  690. . substr($collation, 0, strpos($collation, '_'))
  691. . ' COLLATE ' . $collation;
  692. } else {
  693. $create_query .= ' DEFAULT CHARACTER SET ' . $collation;
  694. }
  695. }
  696. $create_query .= ';' . $crlf;
  697. if (! PMA_exportOutputHandler($create_query)) {
  698. return false;
  699. }
  700. if (isset($GLOBALS['sql_backquotes'])
  701. && ((isset($GLOBALS['sql_compatibility'])
  702. && $GLOBALS['sql_compatibility'] == 'NONE')
  703. || PMA_DRIZZLE)
  704. ) {
  705. $result = PMA_exportOutputHandler(
  706. 'USE ' . PMA_Util::backquoteCompat($db, $compat)
  707. . ';' . $crlf
  708. );
  709. } else {
  710. $result = PMA_exportOutputHandler('USE ' . $db . ';' . $crlf);
  711. }
  712. return $result;
  713. } else {
  714. return true;
  715. }
  716. }
  717. /**
  718. * Outputs database header
  719. *
  720. * @param string $db Database name
  721. *
  722. * @return bool Whether it succeeded
  723. */
  724. public function exportDBHeader($db)
  725. {
  726. if (isset($GLOBALS['sql_compatibility'])) {
  727. $compat = $GLOBALS['sql_compatibility'];
  728. } else {
  729. $compat = 'NONE';
  730. }
  731. $head = $this->_exportComment()
  732. . $this->_exportComment(
  733. __('Database:') . ' '
  734. . (isset($GLOBALS['sql_backquotes'])
  735. ? PMA_Util::backquoteCompat($db, $compat)
  736. : '\'' . $db . '\'')
  737. )
  738. . $this->_exportComment();
  739. return PMA_exportOutputHandler($head);
  740. }
  741. /**
  742. * Outputs database footer
  743. *
  744. * @param string $db Database name
  745. *
  746. * @return bool Whether it succeeded
  747. */
  748. public function exportDBFooter($db)
  749. {
  750. global $crlf;
  751. $result = true;
  752. //add indexes to the sql dump file
  753. if (isset($GLOBALS['sql_indexes'])) {
  754. $result = PMA_exportOutputHandler($GLOBALS['sql_indexes']);
  755. unset($GLOBALS['sql_indexes']);
  756. }
  757. //add auto increments to the sql dump file
  758. if (isset($GLOBALS['sql_auto_increments'])) {
  759. $result = PMA_exportOutputHandler($GLOBALS['sql_auto_increments']);
  760. unset($GLOBALS['sql_auto_increments']);
  761. }
  762. //add constraints to the sql dump file
  763. if (isset($GLOBALS['sql_constraints'])) {
  764. $result = PMA_exportOutputHandler($GLOBALS['sql_constraints']);
  765. unset($GLOBALS['sql_constraints']);
  766. }
  767. if (($GLOBALS['sql_structure_or_data'] == 'structure'
  768. || $GLOBALS['sql_structure_or_data'] == 'structure_and_data')
  769. && isset($GLOBALS['sql_procedure_function'])
  770. ) {
  771. $text = '';
  772. $delimiter = '$$';
  773. if (PMA_MYSQL_INT_VERSION > 50100) {
  774. $event_names = $GLOBALS['dbi']->fetchResult(
  775. 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE'
  776. . ' EVENT_SCHEMA= \''
  777. . PMA_Util::sqlAddSlashes($db, true)
  778. . '\';'
  779. );
  780. } else {
  781. $event_names = array();
  782. }
  783. if ($event_names) {
  784. $text .= $crlf
  785. . 'DELIMITER ' . $delimiter . $crlf;
  786. $text .=
  787. $this->_exportComment()
  788. . $this->_exportComment(__('Events'))
  789. . $this->_exportComment();
  790. foreach ($event_names as $event_name) {
  791. if (! empty($GLOBALS['sql_drop_table'])) {
  792. $text .= 'DROP EVENT '
  793. . PMA_Util::backquote($event_name)
  794. . $delimiter . $crlf;
  795. }
  796. $text .= $GLOBALS['dbi']
  797. ->getDefinition($db, 'EVENT', $event_name)
  798. . $delimiter . $crlf . $crlf;
  799. }
  800. $text .= 'DELIMITER ;' . $crlf;
  801. }
  802. if (! empty($text)) {
  803. $result = PMA_exportOutputHandler($text);
  804. }
  805. }
  806. return $result;
  807. }
  808. /**
  809. * Returns a stand-in CREATE definition to resolve view dependencies
  810. *
  811. * @param string $db the database name
  812. * @param string $view the view name
  813. * @param string $crlf the end of line sequence
  814. *
  815. * @return string resulting definition
  816. */
  817. public function getTableDefStandIn($db, $view, $crlf)
  818. {
  819. $create_query = '';
  820. if (! empty($GLOBALS['sql_drop_table'])) {
  821. $create_query .= 'DROP VIEW IF EXISTS '
  822. . PMA_Util::backquote($view)
  823. . ';' . $crlf;
  824. }
  825. $create_query .= 'CREATE TABLE ';
  826. if (isset($GLOBALS['sql_if_not_exists'])
  827. && $GLOBALS['sql_if_not_exists']
  828. ) {
  829. $create_query .= 'IF NOT EXISTS ';
  830. }
  831. $create_query .= PMA_Util::backquote($view) . ' (' . $crlf;
  832. $tmp = array();
  833. $columns = $GLOBALS['dbi']->getColumnsFull($db, $view);
  834. foreach ($columns as $column_name => $definition) {
  835. $tmp[] = PMA_Util::backquote($column_name) . ' ' .
  836. $definition['Type'] . $crlf;
  837. }
  838. $create_query .= implode(',', $tmp) . ');';
  839. return($create_query);
  840. }
  841. /**
  842. * Returns CREATE definition that matches $view's structure
  843. *
  844. * @param string $db the database name
  845. * @param string $view the view name
  846. * @param string $crlf the end of line sequence
  847. * @param bool $add_semicolon whether to add semicolon and end-of-line at
  848. * the end
  849. *
  850. * @return string resulting schema
  851. */
  852. private function _getTableDefForView(
  853. $db,
  854. $view,
  855. $crlf,
  856. $add_semicolon = true
  857. ) {
  858. $create_query = "CREATE TABLE";
  859. if (isset($GLOBALS['sql_if_not_exists'])) {
  860. $create_query .= " IF NOT EXISTS ";
  861. }
  862. $create_query .= PMA_Util::backquote($view) . "(" . $crlf;
  863. $columns = $GLOBALS['dbi']->getColumns($db, $view, null, true);
  864. $firstCol = true;
  865. foreach ($columns as $column) {
  866. $extracted_columnspec = PMA_Util::extractColumnSpec($column['Type']);
  867. if (! $firstCol) {
  868. $create_query .= "," . $crlf;
  869. }
  870. $create_query .= " " . PMA_Util::backquote($column['Field']);
  871. $create_query .= " " . $column['Type'];
  872. if ($extracted_columnspec['can_contain_collation']
  873. && ! empty($column['Collation'])
  874. ) {
  875. $create_query .= " COLLATE " . $column['Collation'];
  876. }
  877. if ($column['Null'] == 'NO') {
  878. $create_query .= " NOT NULL";
  879. }
  880. if (isset($column['Default'])) {
  881. $create_query .= " DEFAULT '"
  882. . PMA_Util::sqlAddSlashes($column['Default']) . "'";
  883. } else if ($column['Null'] == 'YES') {
  884. $create_query .= " DEFAULT NULL";
  885. }
  886. if (! empty($column['Comment'])) {
  887. $create_query .= " COMMENT '"
  888. . PMA_Util::sqlAddSlashes($column['Comment']) . "'";
  889. }
  890. $firstCol = false;
  891. }
  892. $create_query .= $crlf . ")" . ($add_semicolon ? ';' : '') . $crlf;
  893. if (isset($GLOBALS['sql_compatibility'])) {
  894. $compat = $GLOBALS['sql_compatibility'];
  895. } else {
  896. $compat = 'NONE';
  897. }
  898. if ($compat == 'MSSQL') {
  899. $create_query = $this->_makeCreateTableMSSQLCompatible(
  900. $create_query
  901. );
  902. }
  903. return $create_query;
  904. }
  905. /**
  906. * Returns $table's CREATE definition
  907. *
  908. * @param string $db the database name
  909. * @param string $table the table name
  910. * @param string $crlf the end of line sequence
  911. * @param string $error_url the url to go back in case
  912. * of error
  913. * @param bool $show_dates whether to include creation/
  914. * update/check dates
  915. * @param bool $add_semicolon whether to add semicolon and
  916. * end-of-line at the end
  917. * @param bool $view whether we're handling a view
  918. * @param bool $update_indexes_increments whether we need to update
  919. * two global variables
  920. *
  921. * @return string resulting schema
  922. */
  923. public function getTableDef(
  924. $db,
  925. $table,
  926. $crlf,
  927. $error_url,
  928. $show_dates = false,
  929. $add_semicolon = true,
  930. $view = false,
  931. $update_indexes_increments = true
  932. ) {
  933. global $sql_drop_table, $sql_backquotes, $sql_constraints,
  934. $sql_constraints_query, $sql_indexes, $sql_indexes_query,
  935. $sql_auto_increments,$sql_drop_foreign_keys;
  936. $schema_create = '';
  937. $auto_increment = '';
  938. $new_crlf = $crlf;
  939. if (isset($GLOBALS['sql_compatibility'])) {
  940. $compat = $GLOBALS['sql_compatibility'];
  941. } else {
  942. $compat = 'NONE';
  943. }
  944. // need to use PMA_DatabaseInterface::QUERY_STORE
  945. // with $GLOBALS['dbi']->numRows() in mysqli
  946. $result = $GLOBALS['dbi']->query(
  947. 'SHOW TABLE STATUS FROM ' . PMA_Util::backquote($db)
  948. . ' LIKE \'' . PMA_Util::sqlAddSlashes($table, true) . '\'',
  949. null,
  950. PMA_DatabaseInterface::QUERY_STORE
  951. );
  952. if ($result != false) {
  953. if ($GLOBALS['dbi']->numRows($result) > 0) {
  954. $tmpres = $GLOBALS['dbi']->fetchAssoc($result);
  955. if (PMA_DRIZZLE && $show_dates) {
  956. // Drizzle doesn't give Create_time and Update_time in
  957. // SHOW TABLE STATUS, add it
  958. $sql ="SELECT
  959. TABLE_CREATION_TIME AS Create_time,
  960. TABLE_UPDATE_TIME AS Update_time
  961. FROM data_dictionary.TABLES
  962. WHERE TABLE_SCHEMA = '"
  963. . PMA_Util::sqlAddSlashes($db) . "'
  964. AND TABLE_NAME = '"
  965. . PMA_Util::sqlAddSlashes($table) . "'";
  966. $tmpres = array_merge(
  967. $GLOBALS['dbi']->fetchSingleRow($sql), $tmpres
  968. );
  969. }
  970. // Here we optionally add the AUTO_INCREMENT next value,
  971. // but starting with MySQL 5.0.24, the clause is already included
  972. // in SHOW CREATE TABLE so we'll remove it below
  973. // It's required for Drizzle because SHOW CREATE TABLE uses
  974. // the value from table's creation time
  975. if (isset($GLOBALS['sql_auto_increment'])
  976. && ! empty($tmpres['Auto_increment'])
  977. ) {
  978. $auto_increment .= ' AUTO_INCREMENT='
  979. . $tmpres['Auto_increment'] . ' ';
  980. }
  981. if ($show_dates
  982. && isset($tmpres['Create_time'])
  983. && ! empty($tmpres['Create_time'])
  984. ) {
  985. $schema_create .= $this->_exportComment(
  986. __('Creation:') . ' '
  987. . PMA_Util::localisedDate(
  988. strtotime($tmpres['Create_time'])
  989. )
  990. );
  991. $new_crlf = $this->_exportComment() . $crlf;
  992. }
  993. if ($show_dates
  994. && isset($tmpres['Update_time'])
  995. && ! empty($tmpres['Update_time'])
  996. ) {
  997. $schema_create .= $this->_exportComment(
  998. __('Last update:') . ' '
  999. . PMA_Util::localisedDate(
  1000. strtotime($tmpres['Update_time'])
  1001. )
  1002. );
  1003. $new_crlf = $this->_exportComment() . $crlf;
  1004. }
  1005. if ($show_dates
  1006. && isset($tmpres['Check_time'])
  1007. && ! empty($tmpres['Check_time'])
  1008. ) {
  1009. $schema_create .= $this->_exportComment(
  1010. __('Last check:') . ' '
  1011. . PMA_Util::localisedDate(
  1012. strtotime($tmpres['Check_time'])
  1013. )
  1014. );
  1015. $new_crlf = $this->_exportComment() . $crlf;
  1016. }
  1017. }
  1018. $GLOBALS['dbi']->freeResult($result);
  1019. }
  1020. $schema_create .= $new_crlf;
  1021. // no need to generate a DROP VIEW here, it was done earlier
  1022. if (! empty($sql_drop_table) && ! PMA_Table::isView($db, $table)) {
  1023. $schema_create .= 'DROP TABLE IF EXISTS '
  1024. . PMA_Util::backquote($table, $sql_backquotes) . ';'
  1025. . $crlf;
  1026. }
  1027. // Complete table dump,
  1028. // Whether to quote table and column names or not
  1029. // Drizzle always quotes names
  1030. if (! PMA_DRIZZLE) {
  1031. if ($sql_backquotes) {
  1032. $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 1');
  1033. } else {
  1034. $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 0');
  1035. }
  1036. }
  1037. // I don't see the reason why this unbuffered query could cause problems,
  1038. // because SHOW CREATE TABLE returns only one row, and we free the
  1039. // results below. Nonetheless, we got 2 user reports about this
  1040. // (see bug 1562533) so I removed the unbuffered mode.
  1041. // $result = $GLOBALS['dbi']->query('SHOW CREATE TABLE ' . backquote($db)
  1042. // . '.' . backquote($table), null, PMA_DatabaseInterface::QUERY_UNBUFFERED);
  1043. //
  1044. // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not
  1045. // produce a displayable result for the default value of a BIT
  1046. // column, nor does the mysqldump command. See MySQL bug 35796
  1047. $result = $GLOBALS['dbi']->tryQuery(
  1048. 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.'
  1049. . PMA_Util::backquote($table)
  1050. );
  1051. // an error can happen, for example the table is crashed
  1052. $tmp_error = $GLOBALS['dbi']->getError();
  1053. if ($tmp_error) {
  1054. return $this->_exportComment(__('in use') . '(' . $tmp_error . ')');
  1055. }
  1056. if ($result != false && ($row = $GLOBALS['dbi']->fetchRow($result))) {
  1057. $create_query = $row[1];
  1058. unset($row);
  1059. // Convert end of line chars to one that we want (note that MySQL
  1060. // doesn't return query it will accept in all cases)
  1061. if (strpos($create_query, "(\r\n ")) {
  1062. $create_query = str_replace("\r\n", $crlf, $create_query);
  1063. } elseif (strpos($create_query, "(\n ")) {
  1064. $create_query = str_replace("\n", $crlf, $create_query);
  1065. } elseif (strpos($create_query, "(\r ")) {
  1066. $create_query = str_replace("\r", $crlf, $create_query);
  1067. }
  1068. /*
  1069. * Drop database name from VIEW creation.
  1070. *
  1071. * This is a bit tricky, but we need to issue SHOW CREATE TABLE with
  1072. * database name, but we don't want name to show up in CREATE VIEW
  1073. * statement.
  1074. */
  1075. if ($view) {
  1076. $create_query = preg_replace(
  1077. '/' . preg_quote(PMA_Util::backquote($db)) . '\./',
  1078. '',
  1079. $create_query
  1080. );
  1081. }
  1082. // Should we use IF NOT EXISTS?
  1083. if (isset($GLOBALS['sql_if_not_exists'])) {
  1084. $create_query = preg_replace(
  1085. '/^CREATE TABLE/',
  1086. 'CREATE TABLE IF NOT EXISTS',
  1087. $create_query
  1088. );
  1089. }
  1090. if ($compat == 'MSSQL') {
  1091. $create_query = $this->_makeCreateTableMSSQLCompatible(
  1092. $create_query
  1093. );
  1094. }
  1095. // Drizzle (checked on 2011.03.13) returns ROW_FORMAT surrounded
  1096. // with quotes, which is not accepted by parser
  1097. if (PMA_DRIZZLE) {
  1098. $create_query = preg_replace(
  1099. '/ROW_FORMAT=\'(\S+)\'/',
  1100. 'ROW_FORMAT=$1',
  1101. $create_query
  1102. );
  1103. }
  1104. //are there any constraints to cut out?
  1105. if (preg_match('@CONSTRAINT|KEY@', $create_query)) {
  1106. $has_constraints = 0;
  1107. $has_indexes = 0;
  1108. //if there are constraints
  1109. if (preg_match(
  1110. '@CONSTRAINT@',
  1111. $create_query
  1112. )) {
  1113. $has_constraints = 1;
  1114. // comments -> constraints for dumped tables
  1115. if (! isset($sql_constraints)) {
  1116. if (isset($GLOBALS['no_constraints_comments'])) {
  1117. $sql_constraints = '';
  1118. } else {
  1119. $sql_constraints = $crlf
  1120. . $this->_exportComment()
  1121. . $this->_exportComment(
  1122. __('Constraints for dumped tables')
  1123. )
  1124. . $this->_exportComment();
  1125. }
  1126. }
  1127. // comments for current table
  1128. if (! isset($GLOBALS['no_constraints_comments'])) {
  1129. $sql_constraints .= $crlf
  1130. . $this->_exportComment()
  1131. . $this->_exportComment(
  1132. __('Constraints for table')
  1133. . ' '
  1134. . PMA_Util::backquoteCompat($table, $compat)
  1135. )
  1136. . $this->_exportComment();
  1137. }
  1138. $sql_constraints_query .= 'ALTER TABLE '
  1139. . PMA_Util::backquoteCompat($table, $compat)
  1140. . $crlf;
  1141. $sql_constraints .= 'ALTER TABLE '
  1142. . PMA_Util::backquoteCompat($table, $compat)
  1143. . $crlf;
  1144. $sql_drop_foreign_keys .= 'ALTER TABLE '
  1145. . PMA_Util::backquoteCompat($db, $compat) . '.'
  1146. . PMA_Util::backquoteCompat($table, $compat)
  1147. . $crlf;
  1148. }
  1149. //if there are indexes
  1150. // (look for KEY followed by whitespace to avoid matching
  1151. // keyworks like PACK_KEYS)
  1152. if ($update_indexes_increments && preg_match(
  1153. '@KEY[\s]+@',
  1154. $create_query
  1155. )) {
  1156. $has_indexes = 1;
  1157. // comments -> indexes for dumped tables
  1158. if (! isset($sql_indexes)) {
  1159. if (isset($GLOBALS['no_constraints_comments'])) {
  1160. $sql_indexes = '';
  1161. } else {
  1162. $sql_indexes = $crlf
  1163. . $this->_exportComment()
  1164. . $this->_exportComment(
  1165. __('Indexes for dumped tables')
  1166. )
  1167. . $this->_exportComment();
  1168. }
  1169. }
  1170. // comments for current table
  1171. if (! isset($GLOBALS['no_constraints_comments'])) {
  1172. $sql_indexes .= $crlf
  1173. . $this->_exportComment()
  1174. . $this->_exportComment(
  1175. __('Indexes for table')
  1176. . ' '
  1177. . PMA_Util::backquoteCompat($table, $compat)
  1178. )
  1179. . $this->_exportComment();
  1180. }
  1181. $sql_indexes_query .= 'ALTER TABLE '
  1182. . PMA_Util::backquoteCompat($table, $compat)
  1183. . $crlf;
  1184. $sql_indexes .= 'ALTER TABLE '
  1185. . PMA_Util::backquoteCompat($table, $compat)
  1186. . $crlf;
  1187. }
  1188. if ($update_indexes_increments && preg_match(
  1189. '@AUTO_INCREMENT@',
  1190. $create_query
  1191. )) {
  1192. // comments -> auto increments for dumped tables
  1193. if (! isset($sql_auto_increments)) {
  1194. if (isset($GLOBALS['no_constraints_comments'])) {
  1195. $sql_auto_increments = '';
  1196. } else {
  1197. $sql_auto_increments = $crlf
  1198. . $this->_exportComment()
  1199. . $this->_exportComment(
  1200. __('AUTO_INCREMENT for dumped tables')
  1201. )
  1202. . $this->_exportComment();
  1203. }
  1204. }
  1205. // comments for current table
  1206. if (! isset($GLOBALS['no_constraints_comments'])) {
  1207. $sql_auto_increments .= $crlf
  1208. . $this->_exportComment()
  1209. . $this->_exportComment(
  1210. __('AUTO_INCREMENT for table')
  1211. . ' '
  1212. . PMA_Util::backquoteCompat($table, $compat)
  1213. )
  1214. . $this->_exportComment();
  1215. }
  1216. $sql_auto_increments .= 'ALTER TABLE '
  1217. . PMA_Util::backquoteCompat($table, $compat)
  1218. . $crlf;
  1219. }
  1220. // Split the query into lines, so we can easily handle it.
  1221. // We know lines are separated by $crlf (done few lines above).
  1222. $sql_lines = explode($crlf, $create_query);
  1223. $sql_count = count($sql_lines);
  1224. // lets find first line with constraints
  1225. $first_occur = -1;
  1226. for ($i = 0; $i < $sql_count; $i++) {
  1227. if (preg_match(
  1228. '@[\s]+(CONSTRAINT|KEY)@',
  1229. $sql_lines[$i]
  1230. ) && $first_occur == -1) {
  1231. $first_occur = $i;
  1232. }
  1233. }
  1234. for ($k = 0; $k < $sql_count; $k++) {
  1235. if ($update_indexes_increments && preg_match(
  1236. '( AUTO_INCREMENT | AUTO_INCREMENT,| AUTO_INCREMENT$)',
  1237. $sql_lines[$k]
  1238. )) {
  1239. //removes extra space at the beginning, if there is
  1240. $sql_lines[$k] = ltrim($sql_lines[$k], ' ');
  1241. //creates auto increment code
  1242. $sql_auto_increments .= "MODIFY " . $sql_lines[$k];
  1243. //removes auto increment code from table definition
  1244. $sql_lines[$k] = str_replace(
  1245. " AUTO_INCREMENT", "", $sql_lines[$k]
  1246. );
  1247. }
  1248. if ($update_indexes_increments && preg_match(
  1249. '@[\s]+(AUTO_INCREMENT=)@',
  1250. $sql_lines[$k]
  1251. )) {
  1252. //adds auto increment value
  1253. $increment_value = substr(
  1254. $sql_lines[$k],
  1255. strpos($sql_lines[$k], "AUTO_INCREMENT")
  1256. );
  1257. $increment_value_array = explode(' ', $increment_value);
  1258. $sql_auto_increments .= $increment_value_array[0] . ";";
  1259. }
  1260. }
  1261. if ($sql_auto_increments != '') {
  1262. $sql_auto_increments = substr(
  1263. $sql_auto_increments, 0, -1
  1264. ) . ';';
  1265. }
  1266. // If we really found a constraint
  1267. if ($first_occur != $sql_count) {
  1268. // lets find first line
  1269. $sql_lines[$first_occur - 1] = preg_replace(
  1270. '@,$@',
  1271. '',
  1272. $sql_lines[$first_occur - 1]
  1273. );
  1274. $first = true;
  1275. for ($j = $first_occur; $j < $sql_count; $j++) {
  1276. //removes extra space at the beginning, if there is
  1277. $sql_lines[$j]=ltrim($sql_lines[$j], ' ');
  1278. //if it's a constraint
  1279. if (preg_match(
  1280. '@CONSTRAINT|FOREIGN[\s]+KEY@',
  1281. $sql_lines[$j]
  1282. )) {
  1283. if (! $first) {
  1284. $sql_constraints .= $crlf;
  1285. }
  1286. if (strpos($sql_lines[$j], 'CONSTRAINT') === false) {
  1287. $tmp_str = preg_replace(
  1288. '/(FOREIGN[\s]+KEY)/',
  1289. 'ADD \1',
  1290. $sql_lines[$j]
  1291. );
  1292. $sql_constraints_query .= $tmp_str;
  1293. $sql_constraints .= $tmp_str;
  1294. } else {
  1295. $tmp_str = preg_replace(
  1296. '/(CONSTRAINT)/',
  1297. 'ADD \1',
  1298. $sql_lines[$j]
  1299. );
  1300. $sql_constraints_query .= $tmp_str;
  1301. $sql_constraints .= $tmp_str;
  1302. preg_match(
  1303. '/(CONSTRAINT)([\s])([\S]*)([\s])/',
  1304. $sql_lines[$j],
  1305. $matches
  1306. );
  1307. if (! $first) {
  1308. $sql_drop_foreign_keys .= ', ';
  1309. }
  1310. $sql_drop_foreign_keys .= 'DROP FOREIGN KEY '
  1311. . $matches[3];
  1312. }
  1313. $first = false;
  1314. } else if ($update_indexes_increments && preg_match(
  1315. '@KEY[\s]+@',
  1316. $sql_lines[$j]
  1317. )) {
  1318. //if it's a index
  1319. $tmp_str = " ADD " . $sql_lines[$j];
  1320. $sql_indexes_query .= $tmp_str;
  1321. $sql_indexes .= $tmp_str;
  1322. } else {
  1323. break;
  1324. }
  1325. }
  1326. //removes superfluous comma at the end
  1327. $sql_indexes = rtrim($sql_indexes, ',');
  1328. $sql_indexes_query = rtrim($sql_indexes_query, ',');
  1329. //removes superfluous semicolon at the end
  1330. if ($has_constraints == 1) {
  1331. $sql_constraints .= ';' . $crlf;
  1332. $sql_constraints_query .= ';';
  1333. }
  1334. if ($has_indexes == 1) {
  1335. $sql_indexes .= ';' . $crlf;
  1336. $sql_indexes_query .= ';';
  1337. }
  1338. //remove indexes and constraints from the $create_query
  1339. $create_query = implode(
  1340. $crlf,
  1341. array_slice($sql_lines, 0, $first_occur)
  1342. )
  1343. . $crlf
  1344. . implode(
  1345. $crlf,
  1346. array_slice($sql_lines, $j, $sql_count - 1)
  1347. );
  1348. unset($sql_lines);
  1349. }
  1350. }
  1351. $schema_create .= $create_query;
  1352. }
  1353. // remove a possible "AUTO_INCREMENT = value" clause
  1354. // that could be there starting with MySQL 5.0.24
  1355. // in Drizzle it's useless as it contains the value given at table
  1356. // creation time
  1357. $schema_create = preg_replace(
  1358. '/AUTO_INCREMENT\s*=\s*([0-9])+/',
  1359. '',
  1360. $schema_create
  1361. );
  1362. $schema_create .= ($compat != 'MSSQL') ? $auto_increment : '';
  1363. $GLOBALS['dbi']->freeResult($result);
  1364. return $schema_create . ($add_semicolon ? ';' . $crlf : '');
  1365. } // end of the 'getTableDef()' function
  1366. /**
  1367. * Returns $table's comments, relations etc.
  1368. *
  1369. * @param string $db database name
  1370. * @param string $table table name
  1371. * @param string $crlf end of line sequence
  1372. * @param bool $do_relation whether to include relation comments
  1373. * @param bool $do_mime whether to include mime comments
  1374. *
  1375. * @return string resulting comments
  1376. */
  1377. private function _getTableComments(
  1378. $db,
  1379. $table,
  1380. $crlf,
  1381. $do_relation = false,
  1382. $do_mime = false
  1383. ) {
  1384. global $cfgRelation, $sql_backquotes;
  1385. $schema_create = '';
  1386. // Check if we can use Relations
  1387. if ($do_relation && ! empty($cfgRelation['relation'])) {
  1388. // Find which tables are related with the current one and write it in
  1389. // an array
  1390. $res_rel = PMA_getForeigners($db, $table);
  1391. if ($res_rel && count($res_rel) > 0) {
  1392. $have_rel = true;
  1393. } else {
  1394. $have_rel = false;
  1395. }
  1396. } else {
  1397. $have_rel = false;
  1398. } // end if
  1399. if ($do_mime && $cfgRelation['mimework']) {
  1400. if (! ($mime_map = PMA_getMIME($db, $table, true))) {
  1401. unset($mime_map);
  1402. }
  1403. }
  1404. if (isset($mime_map) && count($mime_map) > 0) {
  1405. $schema_create .= $this->_possibleCRLF()
  1406. . $this->_exportComment()
  1407. . $this->_exportComment(
  1408. __('MIME TYPES FOR TABLE') . ' '
  1409. . PMA_Util::backquote($table, $sql_backquotes) . ':'
  1410. );
  1411. @reset($mime_map);
  1412. foreach ($mime_map as $mime_field => $mime) {
  1413. $schema_create .=
  1414. $this->_exportComment(
  1415. ' '
  1416. . PMA_Util::backquote($mime_field, $sql_backquotes)
  1417. )
  1418. . $this->_exportComment(
  1419. ' '
  1420. . PMA_Util::backquote(
  1421. $mime['mimetype'],
  1422. $sql_backquotes
  1423. )
  1424. );
  1425. }
  1426. $schema_create .= $this->_exportComment();
  1427. }
  1428. if ($have_rel) {
  1429. $schema_create .= $this->_possibleCRLF()
  1430. . $this->_exportComment()
  1431. . $this->_exportComment(
  1432. __('RELATIONS FOR TABLE') . ' '
  1433. . PMA_Util::backquote($table, $sql_backquotes)
  1434. . ':'
  1435. );
  1436. foreach ($res_rel as $rel_field => $rel) {
  1437. $schema_create .=
  1438. $this->_exportComment(
  1439. ' '
  1440. . PMA_Util::backquote($rel_field, $sql_backquotes)
  1441. )
  1442. . $this->_exportComment(
  1443. ' '
  1444. . PMA_Util::backquote(
  1445. $rel['foreign_table'],
  1446. $sql_backquotes
  1447. )
  1448. . ' -> '
  1449. . PMA_Util::backquote(
  1450. $rel['foreign_field'],
  1451. $sql_backquotes
  1452. )
  1453. );
  1454. }
  1455. $schema_create .= $this->_exportComment();
  1456. }
  1457. return $schema_create;
  1458. } // end of the '_getTableComments()' function
  1459. /**
  1460. * Outputs table's structure
  1461. *
  1462. * @param string $db database name
  1463. * @param string $table table name
  1464. * @param string $crlf the end of line sequence
  1465. * @param string $error_url the url to go back in case of error
  1466. * @param string $export_mode 'create_table','triggers','create_view',
  1467. * 'stand_in'
  1468. * @param string $export_type 'server', 'database', 'table'
  1469. * @param bool $relation whether to include relation comments
  1470. * @param bool $comments whether to include the pmadb-style column
  1471. * comments as comments in the structure; this is
  1472. * deprecated but the parameter is left here
  1473. * because export.php calls exportStructure()
  1474. * also for other export types which use this
  1475. * parameter
  1476. * @param bool $mime whether to include mime comments
  1477. * @param bool $dates whether to include creation/update/check dates
  1478. *
  1479. * @return bool Whether it succeeded
  1480. */
  1481. public function exportStructure(
  1482. $db,
  1483. $table,
  1484. $crlf,
  1485. $error_url,
  1486. $export_mode,
  1487. $export_type,
  1488. $relation = false,
  1489. $comments = false,
  1490. $mime = false,
  1491. $dates = false
  1492. ) {
  1493. if (isset($GLOBALS['sql_compatibility'])) {
  1494. $compat = $GLOBALS['sql_compatibility'];
  1495. } else {
  1496. $compat = 'NONE';
  1497. }
  1498. $formatted_table_name = (isset($GLOBALS['sql_backquotes']))
  1499. ? PMA_Util::backquoteCompat($table, $compat)
  1500. : '\'' . $table . '\'';
  1501. $dump = $this->_possibleCRLF()
  1502. . $this->_exportComment(str_repeat('-', 56))
  1503. . $this->_possibleCRLF()
  1504. . $this->_exportComment();
  1505. switch($export_mode) {
  1506. case 'create_table':
  1507. $dump .= $this->_exportComment(
  1508. __('Table structure for table') . ' ' . $formatted_table_name
  1509. );
  1510. $dump .= $this->_exportComment();
  1511. $dump .= $this->getTableDef($db, $table, $crlf, $error_url, $dates);
  1512. $dump .= $this->_getTableComments($db, $table, $crlf, $relation, $mime);
  1513. break;
  1514. case 'triggers':
  1515. $dump = '';
  1516. $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
  1517. if ($triggers) {
  1518. $dump .= $this->_possibleCRLF()
  1519. . $this->_exportComment()
  1520. . $this->_exportComment(
  1521. __('Triggers') . ' ' . $formatted_table_name
  1522. )
  1523. . $this->_exportComment();
  1524. $delimiter = '//';
  1525. foreach ($triggers as $trigger) {
  1526. if (! empty($GLOBALS['sql_drop_table'])) {
  1527. $dump .= $trigger['drop'] . ';' . $crlf;
  1528. }
  1529. $dump .= 'DELIMITER ' . $delimiter . $crlf;
  1530. $dump .= $trigger['create'];
  1531. $dump .= 'DELIMITER ;' . $crlf;
  1532. }
  1533. }
  1534. break;
  1535. case 'create_view':
  1536. if (empty($GLOBALS['sql_views_as_tables'])) {
  1537. $dump .=
  1538. $this->_exportComment(
  1539. __('Structure for view')
  1540. . ' '
  1541. . $formatted_table_name
  1542. )
  1543. . $this->_exportComment();
  1544. // delete the stand-in table previously created (if any)
  1545. if ($export_type != 'table') {
  1546. $dump .= 'DROP TABLE IF EXISTS '
  1547. . PMA_Util::backquote($table) . ';' . $crlf;
  1548. }
  1549. $dump .= $this->getTableDef(
  1550. $db, $table, $crlf, $error_url, $dates, true, true
  1551. );
  1552. } else {
  1553. $dump .=
  1554. $this->_exportComment(
  1555. sprintf(
  1556. __('Structure for view %s exported as a table'),
  1557. $formatted_table_name
  1558. )
  1559. )
  1560. . $this->_exportComment();
  1561. // delete the stand-in table previously created (if any)
  1562. if ($export_type != 'table') {
  1563. $dump .= 'DROP TABLE IF EXISTS '
  1564. . PMA_Util::backquote($table) . ';' . $crlf;
  1565. }
  1566. $dump .= $this->_getTableDefForView(
  1567. $db, $table, $crlf, true
  1568. );
  1569. }
  1570. break;
  1571. case 'stand_in':
  1572. $dump .=
  1573. $this->_exportComment(
  1574. __('Stand-in structure for view') . ' ' . $formatted_table_name
  1575. )
  1576. . $this->_exportComment();
  1577. // export a stand-in definition to resolve view dependencies
  1578. $dump .= $this->getTableDefStandIn($db, $table, $crlf);
  1579. } // end switch
  1580. // this one is built by getTableDef() to use in table copy/move
  1581. // but not in the case of export
  1582. unset($GLOBALS['sql_constraints_query']);
  1583. return PMA_exportOutputHandler($dump);
  1584. }
  1585. /**
  1586. * Outputs the content of a table in SQL format
  1587. *
  1588. * @param string $db database name
  1589. * @param string $table table name
  1590. * @param string $crlf the end of line sequence
  1591. * @param string $error_url the url to go back in case of error
  1592. * @param string $sql_query SQL query for obtaining data
  1593. *
  1594. * @return bool Whether it succeeded
  1595. */
  1596. public function exportData($db, $table, $crlf, $error_url, $sql_query)
  1597. {
  1598. global $current_row, $sql_backquotes;
  1599. if (isset($GLOBALS['sql_compatibility'])) {
  1600. $compat = $GLOBALS['sql_compatibility'];
  1601. } else {
  1602. $compat = 'NONE';
  1603. }
  1604. $formatted_table_name = (isset($GLOBALS['sql_backquotes']))
  1605. ? PMA_Util::backquoteCompat($table, $compat)
  1606. : '\'' . $table . '\'';
  1607. // Do not export data for a VIEW, unless asked to export the view as a table
  1608. // (For a VIEW, this is called only when exporting a single VIEW)
  1609. if (PMA_Table::isView($db, $table)
  1610. && empty($GLOBALS['sql_views_as_tables'])
  1611. ) {
  1612. $head = $this->_possibleCRLF()
  1613. . $this->_exportComment()
  1614. . $this->_exportComment('VIEW ' . ' ' . $formatted_table_name)
  1615. . $this->_exportComment(__('Data:') . ' ' . __('None'))
  1616. . $this->_exportComment()
  1617. . $this->_possibleCRLF();
  1618. if (! PMA_exportOutputHandler($head)) {
  1619. return false;
  1620. }
  1621. return true;
  1622. }
  1623. // analyze the query to get the true column names, not the aliases
  1624. // (this fixes an undefined index, also if Complete inserts
  1625. // are used, we did not get the true column name in case of aliases)
  1626. $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($sql_query));
  1627. $result = $GLOBALS['dbi']->tryQuery(
  1628. $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED
  1629. );
  1630. // a possible error: the table has crashed
  1631. $tmp_error = $GLOBALS['dbi']->getError();
  1632. if ($tmp_error) {
  1633. return PMA_exportOutputHandler(
  1634. $this->_exportComment(
  1635. __('Error reading data:') . ' (' . $tmp_error . ')'
  1636. )
  1637. );
  1638. }
  1639. if ($result != false) {
  1640. $fields_cnt = $GLOBALS['dbi']->numFields($result);
  1641. // Get field information
  1642. $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
  1643. $field_flags = array();
  1644. for ($j = 0; $j < $fields_cnt; $j++) {
  1645. $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j);
  1646. }
  1647. $field_set = array();
  1648. for ($j = 0; $j < $fields_cnt; $j++) {
  1649. if (isset($analyzed_sql[0]['select_expr'][$j]['column'])) {
  1650. $field_set[$j] = PMA_Util::backquoteCompat(
  1651. $analyzed_sql[0]['select_expr'][$j]['column'],
  1652. $compat,
  1653. $sql_backquotes
  1654. );
  1655. } else {
  1656. $field_set[$j] = PMA_Util::backquoteCompat(
  1657. $fields_meta[$j]->name,
  1658. $compat,
  1659. $sql_backquotes
  1660. );
  1661. }
  1662. }
  1663. if (isset($GLOBALS['sql_type'])
  1664. && $GLOBALS['sql_type'] == 'UPDATE'
  1665. ) {
  1666. // update
  1667. $schema_insert = 'UPDATE ';
  1668. if (isset($GLOBALS['sql_ignore'])) {
  1669. $schema_insert .= 'IGNORE ';
  1670. }
  1671. // avoid EOL blank
  1672. $schema_insert .= PMA_Util::backquoteCompat(
  1673. $table,
  1674. $compat,
  1675. $sql_backquotes
  1676. ) . ' SET';
  1677. } else {
  1678. // insert or replace
  1679. if (isset($GLOBALS['sql_type'])
  1680. && $GLOBALS['sql_type'] == 'REPLACE'
  1681. ) {
  1682. $sql_command = 'REPLACE';
  1683. } else {
  1684. $sql_command = 'INSERT';
  1685. }
  1686. // delayed inserts?
  1687. if (isset($GLOBALS['sql_delayed'])) {
  1688. $insert_delayed = ' DELAYED';
  1689. } else {
  1690. $insert_delayed = '';
  1691. }
  1692. // insert ignore?
  1693. if (isset($GLOBALS['sql_type'])
  1694. && $GLOBALS['sql_type'] == 'INSERT'
  1695. && isset($GLOBALS['sql_ignore'])
  1696. ) {
  1697. $insert_delayed .= ' IGNORE';
  1698. }
  1699. //truncate table before insert
  1700. if (isset($GLOBALS['sql_truncate'])
  1701. && $GLOBALS['sql_truncate']
  1702. && $sql_command == 'INSERT'
  1703. ) {
  1704. $truncate = 'TRUNCATE TABLE '
  1705. . PMA_Util::backquoteCompat(
  1706. $table,
  1707. $compat,
  1708. $sql_backquotes
  1709. ) . ";";
  1710. $truncatehead = $this->_possibleCRLF()
  1711. . $this->_exportComment()
  1712. . $this->_exportComment(
  1713. __('Truncate table before insert') . ' '
  1714. . $formatted_table_name
  1715. )
  1716. . $this->_exportComment()
  1717. . $crlf;
  1718. PMA_exportOutputHandler($truncatehead);
  1719. PMA_exportOutputHandler($truncate);
  1720. } else {
  1721. $truncate = '';
  1722. }
  1723. // scheme for inserting fields
  1724. if ($GLOBALS['sql_insert_syntax'] == 'complete'
  1725. || $GLOBALS['sql_insert_syntax'] == 'both'
  1726. ) {
  1727. $fields = implode(', ', $field_set);
  1728. $schema_insert = $sql_command . $insert_delayed . ' INTO '
  1729. . PMA_Util::backquoteCompat(
  1730. $table,
  1731. $compat,
  1732. $sql_backquotes
  1733. )
  1734. // avoid EOL blank
  1735. . ' (' . $fields . ') VALUES';
  1736. } else {
  1737. $schema_insert = $sql_command . $insert_delayed . ' INTO '
  1738. . PMA_Util::backquoteCompat(
  1739. $table,
  1740. $compat,
  1741. $sql_backquotes
  1742. )
  1743. . ' VALUES';
  1744. }
  1745. }
  1746. //\x08\\x09, not required
  1747. $search = array("\x00", "\x0a", "\x0d", "\x1a");
  1748. $replace = array('\0', '\n', '\r', '\Z');
  1749. $current_row = 0;
  1750. $query_size = 0;
  1751. if (($GLOBALS['sql_insert_syntax'] == 'extended'
  1752. || $GLOBALS['sql_insert_syntax'] == 'both')
  1753. && (! isset($GLOBALS['sql_type'])
  1754. || $GLOBALS['sql_type'] != 'UPDATE')
  1755. ) {
  1756. $separator = ',';
  1757. $schema_insert .= $crlf;
  1758. } else {
  1759. $separator = ';';
  1760. }
  1761. while ($row = $GLOBALS['dbi']->fetchRow($result)) {
  1762. if ($current_row == 0) {
  1763. $head = $this->_possibleCRLF()
  1764. . $this->_exportComment()
  1765. . $this->_exportComment(
  1766. __('Dumping data for table') . ' '
  1767. . $formatted_table_name
  1768. )
  1769. . $this->_exportComment()
  1770. . $crlf;
  1771. if (! PMA_exportOutputHandler($head)) {
  1772. return false;
  1773. }
  1774. }
  1775. // We need to SET IDENTITY_INSERT ON for MSSQL
  1776. if (isset($GLOBALS['sql_compatibility'])
  1777. && $GLOBALS['sql_compatibility'] == 'MSSQL'
  1778. && $current_row == 0
  1779. ) {
  1780. if (! PMA_exportOutputHandler(
  1781. 'SET IDENTITY_INSERT '
  1782. . PMA_Util::backquoteCompat(
  1783. $table,
  1784. $compat
  1785. )
  1786. . ' ON ;' . $crlf
  1787. )) {
  1788. return false;
  1789. }
  1790. }
  1791. $current_row++;
  1792. $values = array();
  1793. for ($j = 0; $j < $fields_cnt; $j++) {
  1794. // NULL
  1795. if (! isset($row[$j]) || is_null($row[$j])) {
  1796. $values[] = 'NULL';
  1797. } elseif ($fields_meta[$j]->numeric
  1798. && $fields_meta[$j]->type != 'timestamp'
  1799. && ! $fields_meta[$j]->blob
  1800. ) {
  1801. // a number
  1802. // timestamp is numeric on some MySQL 4.1, BLOBs are
  1803. // sometimes numeric
  1804. $values[] = $row[$j];
  1805. } elseif (stristr($field_flags[$j], 'BINARY') !== false
  1806. && isset($GLOBALS['sql_hex_for_binary'])
  1807. ) {
  1808. // a true BLOB
  1809. // - mysqldump only generates hex data when the --hex-blob
  1810. // option is used, for fields having the binary attribute
  1811. // no hex is generated
  1812. // - a TEXT field returns type blob but a real blob
  1813. // returns also the 'binary' flag
  1814. // empty blobs need to be different, but '0' is also empty
  1815. // :-(
  1816. if (empty($row[$j]) && $row[$j] != '0') {
  1817. $values[] = '\'\'';
  1818. } else {
  1819. $values[] = '0x' . bin2hex($row[$j]);
  1820. }
  1821. } elseif ($fields_meta[$j]->type == 'bit') {
  1822. // detection of 'bit' works only on mysqli extension
  1823. $values[] = "b'" . PMA_Util::sqlAddSlashes(
  1824. PMA_Util::printableBitValue(
  1825. $row[$j], $fields_meta[$j]->length
  1826. )
  1827. )
  1828. . "'";
  1829. } else {
  1830. // something else -> treat as a string
  1831. $values[] = '\''
  1832. . str_replace(
  1833. $search, $replace,
  1834. PMA_Util::sqlAddSlashes($row[$j])
  1835. )
  1836. . '\'';
  1837. } // end if
  1838. } // end for
  1839. // should we make update?
  1840. if (isset($GLOBALS['sql_type'])
  1841. && $GLOBALS['sql_type'] == 'UPDATE'
  1842. ) {
  1843. $insert_line = $schema_insert;
  1844. for ($i = 0; $i < $fields_cnt; $i++) {
  1845. if (0 == $i) {
  1846. $insert_line .= ' ';
  1847. }
  1848. if ($i > 0) {
  1849. // avoid EOL blank
  1850. $insert_line .= ',';
  1851. }
  1852. $insert_line .= $field_set[$i] . ' = ' . $values[$i];
  1853. }
  1854. list($tmp_unique_condition, $tmp_clause_is_unique)
  1855. = PMA_Util::getUniqueCondition(
  1856. $result,
  1857. $fields_cnt,
  1858. $fields_meta,
  1859. $row
  1860. );
  1861. $insert_line .= ' WHERE ' . $tmp_unique_condition;
  1862. unset($tmp_unique_condition, $tmp_clause_is_unique);
  1863. } else {
  1864. // Extended inserts case
  1865. if ($GLOBALS['sql_insert_syntax'] == 'extended'
  1866. || $GLOBALS['sql_insert_syntax'] == 'both'
  1867. ) {
  1868. if ($current_row == 1) {
  1869. $insert_line = $schema_insert . '('
  1870. . implode(', ', $values) . ')';
  1871. } else {
  1872. $insert_line = '(' . implode(', ', $values) . ')';
  1873. $sql_max_size = $GLOBALS['sql_max_query_size'];
  1874. if (isset($sql_max_size)
  1875. && $sql_max_size > 0
  1876. && $query_size + strlen($insert_line) > $sql_max_size
  1877. ) {
  1878. if (! PMA_exportOutputHandler(';' . $crlf)) {
  1879. return false;
  1880. }
  1881. $query_size = 0;
  1882. $current_row = 1;
  1883. $insert_line = $schema_insert . $insert_line;
  1884. }
  1885. }
  1886. $query_size += strlen($insert_line);
  1887. // Other inserts case
  1888. } else {
  1889. $insert_line = $schema_insert
  1890. . '('
  1891. . implode(', ', $values)
  1892. . ')';
  1893. }
  1894. }
  1895. unset($values);
  1896. if (! PMA_exportOutputHandler(
  1897. ($current_row == 1 ? '' : $separator . $crlf)
  1898. . $insert_line
  1899. )) {
  1900. return false;
  1901. }
  1902. } // end while
  1903. if ($current_row > 0) {
  1904. if (! PMA_exportOutputHandler(';' . $crlf)) {
  1905. return false;
  1906. }
  1907. }
  1908. // We need to SET IDENTITY_INSERT OFF for MSSQL
  1909. if (isset($GLOBALS['sql_compatibility'])
  1910. && $GLOBALS['sql_compatibility'] == 'MSSQL'
  1911. && $current_row > 0
  1912. ) {
  1913. $outputSucceeded = PMA_exportOutputHandler(
  1914. $crlf . 'SET IDENTITY_INSERT '
  1915. . PMA_Util::backquoteCompat($table, $compat)
  1916. . ' OFF;' . $crlf
  1917. );
  1918. if (! $outputSucceeded) {
  1919. return false;
  1920. }
  1921. }
  1922. } // end if ($result != false)
  1923. $GLOBALS['dbi']->freeResult($result);
  1924. return true;
  1925. } // end of the 'exportData()' function
  1926. /**
  1927. * Make a create table statement compatible with MSSQL
  1928. *
  1929. * @param string $create_query MySQL create table statement
  1930. *
  1931. * @return string MSSQL compatible create table statement
  1932. */
  1933. private function _makeCreateTableMSSQLCompatible($create_query)
  1934. {
  1935. // In MSSQL
  1936. // 1. No 'IF NOT EXISTS' in CREATE TABLE
  1937. // 2. DATE field doesn't exists, we will use DATETIME instead
  1938. // 3. UNSIGNED attribute doesn't exist
  1939. // 4. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on
  1940. // FLOAT fields
  1941. // 5. No KEY and INDEX inside CREATE TABLE
  1942. // 6. DOUBLE field doesn't exists, we will use FLOAT instead
  1943. $create_query = preg_replace(
  1944. "/^CREATE TABLE IF NOT EXISTS/",
  1945. 'CREATE TABLE',
  1946. $create_query
  1947. );
  1948. // first we need to replace all lines ended with '" DATE ...,\n'
  1949. // last preg_replace preserve us from situation with date text
  1950. // inside DEFAULT field value
  1951. $create_query = preg_replace(
  1952. "/\" date DEFAULT NULL(,)?\n/",
  1953. '" datetime DEFAULT NULL$1' . "\n",
  1954. $create_query
  1955. );
  1956. $create_query = preg_replace(
  1957. "/\" date NOT NULL(,)?\n/",
  1958. '" datetime NOT NULL$1' . "\n",
  1959. $create_query
  1960. );
  1961. $create_query = preg_replace(
  1962. '/" date NOT NULL DEFAULT \'([^\'])/',
  1963. '" datetime NOT NULL DEFAULT \'$1',
  1964. $create_query
  1965. );
  1966. // next we need to replace all lines ended with ') UNSIGNED ...,'
  1967. // last preg_replace preserve us from situation with unsigned text
  1968. // inside DEFAULT field value
  1969. $create_query = preg_replace(
  1970. "/\) unsigned NOT NULL(,)?\n/",
  1971. ') NOT NULL$1' . "\n",
  1972. $create_query
  1973. );
  1974. $create_query = preg_replace(
  1975. "/\) unsigned DEFAULT NULL(,)?\n/",
  1976. ') DEFAULT NULL$1' . "\n",
  1977. $create_query
  1978. );
  1979. $create_query = preg_replace(
  1980. '/\) unsigned NOT NULL DEFAULT \'([^\'])/',
  1981. ') NOT NULL DEFAULT \'$1',
  1982. $create_query
  1983. );
  1984. // we need to replace all lines ended with
  1985. // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us
  1986. // from situation with int([0-9]{1,}) text inside DEFAULT field
  1987. // value
  1988. $create_query = preg_replace(
  1989. '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/',
  1990. '" $1 DEFAULT NULL$2' . "\n",
  1991. $create_query
  1992. );
  1993. $create_query = preg_replace(
  1994. '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/',
  1995. '" $1 NOT NULL$2' . "\n",
  1996. $create_query
  1997. );
  1998. $create_query = preg_replace(
  1999. '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/',
  2000. '" $1 NOT NULL DEFAULT \'$2',
  2001. $create_query
  2002. );
  2003. // we need to replace all lines ended with
  2004. // '" FLOAT|DOUBLE([0-9,]{1,}) ...,'
  2005. // last preg_replace preserve us from situation with
  2006. // float([0-9,]{1,}) text inside DEFAULT field value
  2007. $create_query = preg_replace(
  2008. '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/',
  2009. '" float DEFAULT NULL$3' . "\n",
  2010. $create_query
  2011. );
  2012. $create_query = preg_replace(
  2013. '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/',
  2014. '" float NOT NULL$3' . "\n",
  2015. $create_query
  2016. );
  2017. $create_query = preg_replace(
  2018. '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/',
  2019. '" float NOT NULL DEFAULT \'$3',
  2020. $create_query
  2021. );
  2022. // @todo remove indexes from CREATE TABLE
  2023. return $create_query;
  2024. }
  2025. }