@@ -88,7 +88,19 @@ class MysqliDb
8888 * @var array
8989 */
9090 protected $ _groupBy = array ();
91-
91+
92+ /**
93+ * Dynamic type list for tempromary locking tables.
94+ * @var array
95+ */
96+ protected $ _tableLocks = array ();
97+
98+ /**
99+ * Variable which holds the current table lock method.
100+ * @var string
101+ */
102+ protected $ _tableLockMethod = "READ " ;
103+
92104 /**
93105 * Dynamic array that holds a combination of where condition/table data value types and parameter references
94106 * @var array
@@ -381,6 +393,28 @@ public function setPrefix($prefix = '')
381393 return $ this ;
382394 }
383395
396+ /**
397+ * Pushes a unprepared statement to the mysqli stack.
398+ * WARNING: Use with caution.
399+ * This method does not escape strings by default so make sure you'll never use it in production.
400+ *
401+ * @author Jonas Barascu
402+ * @param [[Type]] $query [[Description]]
403+ */
404+ private function queryUnprepared ($ query )
405+ {
406+ // Execute query
407+ $ stmt = $ this ->mysqli ()->query ($ query );
408+
409+ // Failed?
410+ if (!$ stmt ){
411+ throw new Exception ("Unprepared Query Failed, ERRNO: " .$ this ->mysqli ()->errno ." ( " .$ this ->mysqli ()->error .") " );
412+ };
413+
414+ // return stmt for future use
415+ return $ stmt ;
416+ }
417+
384418 /**
385419 * Execute raw SQL query.
386420 *
@@ -864,6 +898,123 @@ public function join($joinTable, $joinCondition, $joinType = '')
864898
865899 return $ this ;
866900 }
901+
902+
903+ /**
904+ * This is a basic method which allows you to import raw .CSV data into a table
905+ * Please check out http://dev.mysql.com/doc/refman/5.7/en/load-data.html for a valid .csv file.
906+
907+ * @author Jonas Barascu (Noneatme)
908+ * @param string $importTable The database table where the data will be imported into.
909+ * @param string $importFile The file to be imported. Please use double backslashes \\ and make sure you
910+ * @param string $importSettings An Array defining the import settings as described in the README.md
911+ * @return boolean
912+ */
913+ public function loadData ($ importTable , $ importFile , $ importSettings = null )
914+ {
915+ // We have to check if the file exists
916+ if (!file_exists ($ importFile )) {
917+ // Throw an exception
918+ throw new Exception ("importCSV -> importFile " .$ importFile ." does not exists! " );
919+ return ;
920+ }
921+
922+ // Define the default values
923+ // We will merge it later
924+ $ settings = Array ("fieldChar " => '; ' , "lineChar " => PHP_EOL , "linesToIgnore " => 1 );
925+
926+ // Check the import settings
927+ if (gettype ($ importSettings ) == "array " ) {
928+ // Merge the default array with the custom one
929+ $ settings = array_merge ($ settings , $ importSettings );
930+ }
931+
932+ // Add the prefix to the import table
933+ $ table = self ::$ prefix . $ importTable ;
934+
935+ // Add 1 more slash to every slash so maria will interpret it as a path
936+ $ importFile = str_replace ("\\" , "\\\\" , $ importFile );
937+
938+ // Build SQL Syntax
939+ $ sqlSyntax = sprintf ('LOAD DATA INFILE \'%s \' INTO TABLE %s ' ,
940+ $ importFile , $ table );
941+
942+ // FIELDS
943+ $ sqlSyntax .= sprintf (' FIELDS TERMINATED BY \'%s \'' , $ settings ["fieldChar " ]);
944+ if (isset ($ settings ["fieldEnclosure " ])) {
945+ $ sqlSyntax .= sprintf (' ENCLOSED BY \'%s \'' , $ settings ["fieldEnclosure " ]);
946+ }
947+
948+ // LINES
949+ $ sqlSyntax .= sprintf (' LINES TERMINATED BY \'%s \'' , $ settings ["lineChar " ]);
950+ if (isset ($ settings ["lineStarting " ])) {
951+ $ sqlSyntax .= sprintf (' STARTING BY \'%s \'' , $ settings ["lineStarting " ]);
952+ }
953+
954+ // IGNORE LINES
955+ $ sqlSyntax .= sprintf (' IGNORE %d LINES ' , $ settings ["linesToIgnore " ]);
956+
957+ // Exceute the query unprepared because LOAD DATA only works with unprepared statements.
958+ $ result = $ this ->queryUnprepared ($ sqlSyntax );
959+
960+ // Are there rows modified?
961+ // Let the user know if the import failed / succeeded
962+ return (bool ) $ result ;
963+ }
964+
965+ /**
966+ * This method is usefull for importing XML files into a specific table.
967+ * Check out the LOAD XML syntax for your MySQL server.
968+ *
969+ * @author Jonas Barascu
970+ * @param string $importTable The table in which the data will be imported to.
971+ * @param string $importFile The file which contains the .XML data.
972+ * @param string $importSettings An Array defining the import settings as described in the README.md
973+ *
974+ * @return boolean Returns true if the import succeeded, false if it failed.
975+ */
976+ public function loadXml ($ importTable , $ importFile , $ importSettings = null )
977+ {
978+ // We have to check if the file exists
979+ if (!file_exists ($ importFile )) {
980+ // Does not exists
981+ throw new Exception ("loadXml: Import file does not exists " );
982+ return ;
983+ }
984+
985+ // Create default values
986+ $ settings = Array ("linesToIgnore " => 0 );
987+
988+ // Check the import settings
989+ if (gettype ($ importSettings ) == "array " ) {
990+ $ settings = array_merge ($ settings , $ importSettings );
991+ }
992+
993+ // Add the prefix to the import table
994+ $ table = self ::$ prefix . $ importTable ;
995+
996+ // Add 1 more slash to every slash so maria will interpret it as a path
997+ $ importFile = str_replace ("\\" , "\\\\" , $ importFile );
998+
999+ // Build SQL Syntax
1000+ $ sqlSyntax = sprintf ('LOAD XML INFILE \'%s \' INTO TABLE %s ' ,
1001+ $ importFile , $ table );
1002+
1003+ // FIELDS
1004+ if (isset ($ settings ["rowTag " ])) {
1005+ $ sqlSyntax .= sprintf (' ROWS IDENTIFIED BY \'%s \'' , $ settings ["rowTag " ]);
1006+ }
1007+
1008+ // IGNORE LINES
1009+ $ sqlSyntax .= sprintf (' IGNORE %d LINES ' , $ settings ["linesToIgnore " ]);
1010+
1011+ // Exceute the query unprepared because LOAD XML only works with unprepared statements.
1012+ $ result = $ this ->queryUnprepared ($ sqlSyntax );
1013+
1014+ // Are there rows modified?
1015+ // Let the user know if the import failed / succeeded
1016+ return (bool ) $ result ;
1017+ }
8671018
8681019 /**
8691020 * This method allows you to specify multiple (method chaining optional) ORDER BY statements for SQL queries.
@@ -921,7 +1072,123 @@ public function groupBy($groupByField)
9211072 $ this ->_groupBy [] = $ groupByField ;
9221073 return $ this ;
9231074 }
924-
1075+
1076+
1077+ /**
1078+ * This method sets the current table lock method.
1079+ *
1080+ * @author Jonas Barascu
1081+ * @param string $method The table lock method. Can be READ or WRITE.
1082+ *
1083+ * @throws Exception
1084+ * @return MysqliDb
1085+ */
1086+ public function setLockMethod ($ method )
1087+ {
1088+ // Switch the uppercase string
1089+ switch (strtoupper ($ method )) {
1090+ // Is it READ or WRITE?
1091+ case "READ " || "WRITE " :
1092+ // Succeed
1093+ $ this ->_tableLockMethod = $ method ;
1094+ break ;
1095+ default :
1096+ // Else throw an exception
1097+ throw new Exception ("Bad lock type: Can be either READ or WRITE " );
1098+ break ;
1099+ }
1100+ return $ this ;
1101+ }
1102+
1103+ /**
1104+ * Locks a table for R/W action.
1105+ *
1106+ * @author Jonas Barascu
1107+ * @param string $table The table to be locked. Can be a table or a view.
1108+ *
1109+ * @throws Exception
1110+ * @return MysqliDb if succeeeded;
1111+ */
1112+ public function lock ($ table )
1113+ {
1114+ // Main Query
1115+ $ this ->_query = "LOCK TABLES " ;
1116+
1117+ // Is the table an array?
1118+ if (gettype ($ table ) == "array " ) {
1119+ // Loop trough it and attach it to the query
1120+ foreach ($ table as $ key => $ value ) {
1121+ if (gettype ($ value ) == "string " ) {
1122+ if ($ key > 0 ) {
1123+ $ this ->_query .= ", " ;
1124+ }
1125+ $ this ->_query .= " " .self ::$ prefix .$ value ." " .$ this ->_tableLockMethod ;
1126+ }
1127+ }
1128+ }
1129+ else {
1130+ // Build the table prefix
1131+ $ table = self ::$ prefix . $ table ;
1132+
1133+ // Build the query
1134+ $ this ->_query = "LOCK TABLES " .$ table ." " .$ this ->_tableLockMethod ;
1135+ }
1136+
1137+ // Exceute the query unprepared because LOCK only works with unprepared statements.
1138+ $ result = $ this ->queryUnprepared ($ this ->_query );
1139+
1140+ // Reset the query
1141+ $ this ->reset ();
1142+
1143+ // Are there rows modified?
1144+ if ($ result ) {
1145+ // Return true
1146+ // We can't return ourself because if one table gets locked, all other ones get unlocked!
1147+ return true ;
1148+ }
1149+ // Something went wrong
1150+ else {
1151+ throw new Exception ("Locking of table " .$ table ." failed " );
1152+ }
1153+
1154+ // Return the success value
1155+ return false ;
1156+ }
1157+
1158+ /**
1159+ * Unlocks all tables in a database.
1160+ * Also commits transactions.
1161+ *
1162+ * @author Jonas Barascu
1163+ * @return MysqliDb
1164+ */
1165+ public function unlock ()
1166+ {
1167+ // Build the query
1168+ $ this ->_query = "UNLOCK TABLES " ;
1169+
1170+ // Exceute the query unprepared because UNLOCK and LOCK only works with unprepared statements.
1171+ $ result = $ this ->queryUnprepared ($ this ->_query );
1172+
1173+ // Reset the query
1174+ $ this ->reset ();
1175+
1176+ // Are there rows modified?
1177+ if ($ result ) {
1178+ // return self
1179+ return $ this ;
1180+ }
1181+ // Something went wrong
1182+ else {
1183+ throw new Exception ("Unlocking of tables failed " );
1184+ }
1185+
1186+
1187+ // Return self
1188+ return $ this ;
1189+ }
1190+
1191+
9251192 /**
9261193 * This methods returns the ID of the last inserted item
9271194 *
@@ -2017,4 +2284,4 @@ private function conditionToSql($operator, $val) {
20172284 }
20182285}
20192286
2020- // END class
2287+ // END class
0 commit comments