<?php
Class PHPRC_PDO_MYSQL
{
	
	/**
	 * Returns PDOConnection. (Do not pass any parameter if you want to use the SQL constants in PHPSettings file)
	 * @param String $DATA_SOURCE <br />[Optional]DataSource to connect e.g. LocalHost.<br />
	 * @param String $DATABASE_NAME<br />[Optional]Name of database to load.<br />
	 * @param String $DATABASE_USER<br />[Optional]SQL database authentication username.<br />
	 * @param String $DATABASE_PASSWORD<br />[Optional]SQL database authentication password.<br />
	 * @return PDOHandle <br />PDO Handle connected with requested database.<br />
	 */
	Public Static Function REF_CONNECT
	(
			$DATA_SOURCE = "",
			$DATABASE_NAME = "",
			$DATABASE_USER = "",
			$DATABASE_PASSWORD = "",
			$DB_TYPE = "MYSQL"
	)
	{
		Try
		{
			if
			(
					PHPVC_STR::VAR_IS_BLANK($DATA_SOURCE) === TRUE &&
					PHPVC_STR::VAR_IS_BLANK($DATABASE_NAME) === TRUE &&
					PHPVC_STR::VAR_IS_BLANK($DATABASE_USER) === TRUE &&
					PHPVC_STR::VAR_IS_BLANK($DATABASE_PASSWORD) === TRUE
			)
			{
				$DATA_SOURCE = PHPSET::$SQL_DATA_SOURCE;
				$DATABASE_NAME = PHPSET::$SQL_DATABASE_NAME;
				$DATABASE_USER = PHPSET::$SQL_DATABASE_USER;
				$DATABASE_PASSWORD = PHPSET::$SQL_DATABASE_PASSWORD;
			}
			
			if(PHPVC_STR::VAR_UCASE($DATA_SOURCE) == "LOCALHOST")
			{
				$DATA_SOURCE = "127.0.0.1";
			}
			
			if($DB_TYPE == "MYSQL")
			{
				Return new PDO
				(
						"mysql:host=" . $DATA_SOURCE . ";dbname=" . $DATABASE_NAME . ";charset=utf8",
						$DATABASE_USER,
						$DATABASE_PASSWORD
						
						/*,
						 [
						 PDO::MYSQL_ATTR_SSL_KEY    =>'/etc/mysql/ssl/client-key.pem',
						 PDO::MYSQL_ATTR_SSL_CERT=>'/etc/mysql/ssl/client-cert.pem',
						 PDO::MYSQL_ATTR_SSL_CA    =>'/etc/mysql/ssl/ca-cert.pem'
						 ]*/
				);
			}
			else if($DB_TYPE == "MSSQL")
			{
				Return new PDO
				(
						"mssql:host=" . $DATA_SOURCE . ";dbname=" . $DATABASE_NAME . ";charset=utf8",
						$DATABASE_USER,
						$DATABASE_PASSWORD
				);
			}
			else
			{
				
			}
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			PHPRC_HEADERS::REF_503_SERVICE_UNAVAILABLE();
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			PHPRC_HEADERS::REF_503_SERVICE_UNAVAILABLE();
		}
	}
	
	
	/**
	 * Begins SQL Transaction in given PDO
	 * @param PDOHandle $PDO_HANDLE <br />PDO Handle connected to database.<br />
	 * @return none
	 */
	Public Static Function REF_TRANSACTION_BEGIN($PDO_HANDLE)
	{
		// Validate Parameter
		// --------------------------------------
		If($PDO_HANDLE == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_DB', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			$PDO_HANDLE->beginTransaction();
			//$PDO_HANDLE->query("START TRANSACTION");
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Commits requests made within the currect SQL Transaction.
	 * @param PDOHandle $PDO_HANDLE <br />PDOHandle connected to database.<br />
	 * @return none
	 */
	Public Static Function REF_TRANSACTION_COMMIT($PDO_HANDLE)
	{
		// Validate Parameter
		// --------------------------------------
		If($PDO_HANDLE == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_HANDLE', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			$PDO_HANDLE->commit();
			//$PDO_HANDLE->query("COMMIT");
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Rollbacks the requests made within the currect SQL Transaction.
	 * @param PDOHandle $PDO_HANDLE <br />PDOHandle connected to database.<br />
	 * @return none
	 */
	Public Static Function REF_TRANSACTION_ROLLBACK($PDO_HANDLE)
	{
		// Validate Parameter
		// --------------------------------------
		If($PDO_HANDLE == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_DB', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			$PDO_HANDLE->rollBack();
			//$PDO_HANDLE->query("ROLLBACK");
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Returns Error information as string.
	 * @param PDOStatement $PDO_STATEMENT <br />Prepared and binded PDO statement.<br />
	 * @param Boolean $MESSAGE_ONLY <br />If True, returns only the error message. [Default : False]<br />
	 * @return String <br />Returns error information.<br />
	 */
	Public Static Function REF_ERROR_INFO($PDO_STATEMENT, $MESSAGE_ONLY = False)
	{
		// Validate Parameter
		// --------------------------------------
		If($PDO_STATEMENT == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_STATEMENT', FALSE)));
		}
		
		If($PDO_STATEMENT instanceof PDOStatement === False)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_ARGUMENT_EXCEPTION_INVALID_ARGUMENT_TYPE('PDO_STATEMENT', 'PDOStatement', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			$PDO_ERROR = $PDO_STATEMENT->errorInfo();
			if(empty($PDO_ERROR) === True)
			{
				Return "No PDO Errors found.";
			}
			else
			{
				if($MESSAGE_ONLY === True)
				{
					Return 'SQL Error: ' . $PDO_ERROR[2];
				}
				else
				{
					Return
					'SQLSTATE error code: ' . $PDO_ERROR[0] . ' || ' .
					'Driver-specific error code: ' . $PDO_ERROR[1] . ' || ' .
					'Driver-specific error message: ' . $PDO_ERROR[2];
				}
			}
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Checks if the PDO error is from user-defined errors(RAISERROR).
	 * @param PDOStatement $PDO_STATEMENT <br />Prepared and binded PDO statement.<br />
	 */
	Public Static Function REF_IS_CUSTOM_ERROR($PDO_STATEMENT)
	{
		// Validate Parameter
		// --------------------------------------
		If($PDO_STATEMENT == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_STATEMENT', FALSE)));
		}
		
		If($PDO_STATEMENT instanceof PDOStatement === False)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_ARGUMENT_EXCEPTION_INVALID_ARGUMENT_TYPE('PDO_STATEMENT', 'PDOStatement', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			$PDO_ERROR = $PDO_STATEMENT->errorInfo();
			if(empty($PDO_ERROR) === True)
			{
				Return False;
			}
			else
			{
				if($PDO_ERROR[0] == '45000')
				{
					Return True;
				}
				else
				{
					Return False;
				}
			}
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Executes the PDO Statement query.
	 * @param PDOStatement $PDO_STATEMENT <br />Prepared and binded PDO statement.<br />
	 * @param Boolean $RAISE_ERROR [Optional]<br />Raise SQL error if set to TRUE.<br />
	 * @return Boolean <br />Returns TRUE if success, else raises an error.<br />
	 */
	Public Static Function REF_EXECUTE($PDO_STATEMENT, $RAISE_ERROR = True)
	{
		// Validate Parameter
		// --------------------------------------
		If(isset($PDO_STATEMENT) === False)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_STATEMENT', FALSE)));
		}
		
		If($PDO_STATEMENT instanceof PDOStatement === False)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_ARGUMENT_EXCEPTION_INVALID_ARGUMENT_TYPE('PDO_STATEMENT', 'PDOStatement', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			if($PDO_STATEMENT->execute() === True)
			{
				Return True;
			}
			else if($RAISE_ERROR === False)
			{
				Return Null;
			}
			else
			{
				PHPVC_LOG::VAR_ERROR('PDO ERR Details', PHPRC_PDO_MYSQL::REF_ERROR_INFO($PDO_STATEMENT));
				PHPVC_LOG::VAR_BR();
				Throw new Exception(SELF::REF_ERROR_INFO($PDO_STATEMENT, True));
			}
		}
		Catch(PDOException $PDO_ERR)
		{
		    // Reject Common Errors
		    if(PHPSET::LOCAL_MODE == false)
		    {
		        $ERR_MESSAGE = PHPRC_PDO_MYSQL::REF_ERROR_INFO($PDO_STATEMENT);	        
		        if
		        (
		            (
		                strpos
		                (
		                  $ERR_MESSAGE,
		                  "SQLSTATE error code: 45000 || Driver-specific error code: 1644 || Driver-specific error message: YOU DON'T HAVE ENOUGHT RIGHTS TO ACCESS THIS FEATURE"
		                ) !== false
		            ) ||
		            (
		                strpos
		                (
		                    $ERR_MESSAGE, 
		                    "SQLSTATE error code: 45000 || Driver-specific error code: 1644 || Driver-specific error message: Similar entry already exists"
		                ) !== false
		            )
		        )
		        {
		            Throw $PDO_ERR;
		            return;
		        }
		    }
		    
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			PHPVC_LOG::VAR_ERROR('PDO ERR Details', PHPRC_PDO_MYSQL::REF_ERROR_INFO($PDO_STATEMENT));
			PHPVC_LOG::VAR_BR();
			
			PHPRC_PDO_MYSQL_PARAM::VAR_LOG_DETAILS($PDO_STATEMENT);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			PHPRC_PDO_MYSQL_PARAM::VAR_LOG_DETAILS($PDO_STATEMENT);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	/**
	 * Returns executed PDO Statement result
	 * @param PDOStatement $PDO_STATEMENT <br />Prepared and binded PDO statement.<br />
	 * @param Boolean $RAISE_ERROR [Optional]<br />Raise SQL error if set to TRUE.<br />
	 * @return String[] <br />Result in string array. On error returns NULL.<br />
	 */
	Public Static Function REF_EXECUTE_TO_ARRAY($PDO_STATEMENT, $RAISE_ERROR = True)
	{
		// Validate Parameter
		// --------------------------------------
		If(empty($PDO_STATEMENT) === TRUE)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_STATEMENT', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			if($PDO_STATEMENT->execute() === True)
			{
				$RESULT_ARRAY = $PDO_STATEMENT->fetchAll();
				
				$PDO_STATEMENT->closeCursor();
				Return $RESULT_ARRAY;
			}
			else if($RAISE_ERROR === False)
			{
				Return Null;
			}
			else
			{
				PHPVC_LOG::VAR_ERROR('PDO ERR Details', PHPRC_PDO_MYSQL::REF_ERROR_INFO($PDO_STATEMENT));
				PHPVC_LOG::VAR_BR();
				
				$ERR_INFO = SELF::REF_ERROR_INFO($PDO_STATEMENT, True);
				$PDO_STATEMENT->closeCursor();
				Throw new Exception($ERR_INFO);
			}
		}
		Catch(PDOException $PDO_ERR)
		{
		    // Reject Common Errors
		    if(PHPSET::LOCAL_MODE == false)
		    {
		        $ERR_MESSAGE = PHPRC_PDO_MYSQL::REF_ERROR_INFO($PDO_STATEMENT);
		        if
		        (
		            (
		                strpos
		                (
		                    $ERR_MESSAGE,
		                    "SQLSTATE error code: 45000 || Driver-specific error code: 1644 || Driver-specific error message: YOU DON'T HAVE ENOUGHT RIGHTS TO ACCESS THIS FEATURE"
		                    ) !== false
		                ) ||
		            (
		                strpos
		                (
		                    $ERR_MESSAGE,
		                    "SQLSTATE error code: 45000 || Driver-specific error code: 1644 || Driver-specific error message: Similar entry already exists"
		                    ) !== false
		                )
		            )
		        {
		            Throw $PDO_ERR;
		            return;
		        }
		    }
		    
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			PHPVC_LOG::VAR_ERROR('PDO ERR Details', PHPRC_PDO_MYSQL::REF_ERROR_INFO($PDO_STATEMENT));
			PHPVC_LOG::VAR_BR();
			
			PHPRC_PDO_MYSQL_PARAM::VAR_LOG_DETAILS($PDO_STATEMENT);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			PHPRC_PDO_MYSQL_PARAM::VAR_LOG_DETAILS($PDO_STATEMENT);
			Throw $ERR;
		}
		// --------------------------------------
	}
}



Class PHPRC_PDO_MYSQL_ARRAY
{
	/**
	 * Push DataSet(Array) into Base DataSet(Array).
	 * @param String() $BASE_DATA_SET
	 * @param String() $ADD_DATA_SET
	 * @return String() Result Array
	 */
	Public Static Function REF_MERGE(Array $BASE_DATA_SET, Array $ADD_DATA_SET)
	{
		// Validate Parameter
		// ------------------------------------------------
		if(isset($BASE_DATA_SET) === False)
		{
			return $ADD_DATA_SET;
		}
		if(isset($ADD_DATA_SET) === False)
		{
			return $BASE_DATA_SET;
		}
		// ------------------------------------------------
		
		
		// Actual Function
		// ------------------------------------------------
		Try
		{
			$ARRAY_CTR = 0;
			while($ARRAY_CTR < Count($ADD_DATA_SET))
			{
				$BASE_DATA_SET[count($BASE_DATA_SET)] = $ADD_DATA_SET[$ARRAY_CTR];
				$ARRAY_CTR ++;
			}
			
			return $BASE_DATA_SET;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// ------------------------------------------------
	}
	
	
	
	/**
	 * Converts the PDO result array into JSON
	 * @param String[] $RESULT_ARRAY <br />Array retrieved from the `REF_EXECUTE_TO_ARRAY`.<br />
	 * @return String <br />JSON string result.<br />
	 */
	Public Static Function REF_TO_JSON(Array $RESULT_ARRAY)
	{
		//print_r($RESULT_ARRAY);
		//exit();
		
		// Validate Parameter
		// ------------------------------------------------
		if(isset($RESULT_ARRAY) === False)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(New Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION("RESULT_ARRAY", False)));
		}
		// ------------------------------------------------
		
		
		// Actual Function
		// ------------------------------------------------
		Try
		{
			$RESULT_JSON = "{";
			$RESULT_JSON_ARRAY = [];
			$FIELD_NAMES = SELF::REF_FIELD_NAME($RESULT_ARRAY);
			$FIELD_INDEX = 0;
			
			$JSON_COUNT = SELF::REF_JSON_COUNT($RESULT_ARRAY, $FIELD_NAMES);
			$ROW_INDEX = 0;
			
			while(Count($FIELD_NAMES) > $FIELD_INDEX)
			{
				// Add Field header
				// ........................................
				if($FIELD_INDEX > 0)
				{
					//$RESULT_JSON = $RESULT_JSON . ',';
				}
				// ........................................
				
				// For 2D Array
				if(isset($RESULT_ARRAY[$FIELD_NAMES[$FIELD_INDEX]]) === false)
				{
					//$RESULT_JSON = $RESULT_JSON . Chr(34) . $FIELD_NAMES[$FIELD_INDEX] . Chr(34) . ":{";
					$ROW_INDEX = 0;
					
					// List down the field items
					// ........................................
					while($JSON_COUNT > $ROW_INDEX)
					{
						if($ROW_INDEX > 0)
						{
							//$RESULT_JSON = $RESULT_JSON . ',';
						}
						
						if(isset($RESULT_ARRAY[$ROW_INDEX][$FIELD_NAMES[$FIELD_INDEX]]) === true)
						{
							$RESULT_JSON_ARRAY[$FIELD_NAMES[$FIELD_INDEX]][$ROW_INDEX + 1] = PHPVC_STR::VAR_TO_UTF8($RESULT_ARRAY[$ROW_INDEX][$FIELD_NAMES[$FIELD_INDEX]]);
							//$RESULT_JSON = $RESULT_JSON . Chr(34) . ($ROW_INDEX + 1) . Chr(34) . ":" . Chr(34) . $RESULT_ARRAY[$ROW_INDEX][$FIELD_NAMES[$FIELD_INDEX]]  . Chr(34);
						}
						else
						{
							$RESULT_JSON_ARRAY[$FIELD_NAMES[$FIELD_INDEX]][$ROW_INDEX + 1] = '';
							//$RESULT_JSON = $RESULT_JSON . Chr(34) . ($ROW_INDEX + 1) . Chr(34) . ":" . Chr(34) . Chr(34);
						}
						
						$ROW_INDEX += 1;
					}
					
					//$RESULT_JSON = $RESULT_JSON . "}";
					// ........................................
				}
				
				// For 1D Array
				else if(isset($RESULT_ARRAY[$FIELD_NAMES[$FIELD_INDEX]]))
				{
					$RESULT_JSON_ARRAY[$FIELD_NAMES[$FIELD_INDEX]] = $RESULT_ARRAY[$FIELD_NAMES[$FIELD_INDEX]];
					//$RESULT_JSON = $RESULT_JSON . Chr(34) . $FIELD_NAMES[$FIELD_INDEX] . Chr(34) . ":" . Chr(34) . $RESULT_ARRAY[$FIELD_NAMES[$FIELD_INDEX]] . Chr(34);
				}
				
				//PHPVC_LOG::VAR_COMMENTS("Current Index : Total Columns", $FIELD_INDEX . ' : ' . Count($FIELD_NAMES));
				$FIELD_INDEX += 1;
			}
			
			$RESULT_JSON_ARRAY["JSON_COUNT"] = StrVal($JSON_COUNT);
			//$RESULT_JSON = $RESULT_JSON . "," . Chr(34) . "JSON_COUNT" . Chr(34) . ":" . Chr(34) . $JSON_COUNT . Chr(34);
			//$RESULT_JSON = $RESULT_JSON . "}";
			
			//Return $RESULT_JSON;
			Return PHPRC_JSON::REF_TO_JSON($RESULT_JSON_ARRAY);
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// ------------------------------------------------
	}
	
	/**
	 * Get number of query result (from mixed array with query retul with non-query result)
	 * @param array $RESULT_ARRAY <br />Array containing the query result<br />
	 * @param array $FIELD_NAMES <br /> List of field names related to requested query returns<br />
	 * @throws Exception
	 * @return numeric
	 */
	Public Static Function REF_JSON_COUNT(Array $RESULT_ARRAY, Array $FIELD_NAMES)
	{
		// Validate Parameter
		// ------------------------------------------------
		if(empty($RESULT_ARRAY) === True)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(New Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION("RESULT_ARRAY", False)));
		}
		if(empty($FIELD_NAMES) === True)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(New Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION("FIELD_NAMES", False)));
		}
		// ------------------------------------------------
		
		
		// Actual Function
		// ------------------------------------------------
		Try
		{
			if(empty($RESULT_ARRAY))
			{
				return 0;
			}
			if(count($FIELD_NAMES) <= 0)
			{
				return 0;
			}
			
			
			$BASE_FIELD_NAME = '';
			$FIELD_CTR = 0;
			$ARRAY_CTR = 0;
			$JSON_COUNT = 0;
			
			// Search 2D Indexed field (e.g. ARRAY[0][FIELD])
			while($FIELD_CTR < count($FIELD_NAMES))
			{
				if(isset($RESULT_ARRAY[$FIELD_NAMES[$FIELD_CTR]]) === false)
				{
					// Locate Array 1D Index containing such 2D indexed field
					while($ARRAY_CTR < count($RESULT_ARRAY))
					{
						if(isset($RESULT_ARRAY[$ARRAY_CTR][$FIELD_NAMES[$FIELD_CTR]]))
						{
							$JSON_COUNT ++;
						}
						$ARRAY_CTR ++;
					}
					
					if($JSON_COUNT > 0)
					{
						return $JSON_COUNT;
					}
				}
				$FIELD_CTR ++;
			}
			
			return 0;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// ------------------------------------------------
	}
	
	/**
	 * Check first layer result
	 * @param array $RESULT_ARRAY SQL result array
	 * @param unknown $FIELD_NAME SQL Field  to fetchs
	 * @return String
	 */
	Public Static Function REF_FETCH(Array $RESULT_ARRAY, $FIELD_NAME)
	{
		// Parameter Validation
		PHPVC_AV::VAR_VALIDATE_NULL($RESULT_ARRAY, "RESULT_ARRAY");
		
		// Check 1D Array
		if
		(
				is_array($RESULT_ARRAY[0]) === false &&
				isset($RESULT_ARRAY[$FIELD_NAME])
				)
		{
			return $RESULT_ARRAY[$FIELD_NAME];
		}
		
		// Check 2D array
		else if
		(
				is_array($RESULT_ARRAY[0]) &&
				isset($RESULT_ARRAY[0][$FIELD_NAME])
				)
		{
			return $RESULT_ARRAY[0][$FIELD_NAME];
		}
		
		// Not found
		else
		{
			return null;
		}
	}
	
	/**
	 * Check first layer result
	 * @param array $RESULT_ARRAY SQL result array
	 * @param unknown $FIELD_NAME SQL Field  to fetchs
	 * @return Long
	 */
	Public Static Function REF_FETCH_INT(Array $RESULT_ARRAY, $FIELD_NAME)
	{
		return PHPVC_NUM::VAR_LONGVAL
		(
				self::REF_FETCH
				(
					$RESULT_ARRAY, 
					$FIELD_NAME
				)
		);
	}
	
	/**
	 * Check first layer result
	 * @param array $RESULT_ARRAY SQL result array
	 * @param unknown $FIELD_NAME SQL Field  to fetchs
	 * @return Double
	 */
	Public Static Function REF_FETCH_DOUBLE()
	{
		return PHPVC_NUM::VAR_NVAL
		(
				self::REF_FETCH
				(
						$RESULT_ARRAY,
						$FIELD_NAME
				)
		);
	}
	
	/**
	 * Checks if the requested field exists in the
	 * @param array $RESULT_ARRAY
	 * @param unknown $FIELD_NAME
	 */
	Public Static Function REF_FIELD_CONTAINS(Array $RESULT_ARRAY, $FIELD_NAME)
	{
		$FIELD_NAMES = self::REF_FIELD_NAME($RESULT_ARRAY);
		if(PHPVC_ARRAY::VAR_CONTAINS($FIELD_NAMES, $FIELD_NAME) === true)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * Returns field name list of retrieved array from PDO execute.
	 * @param String[] $RESULT_ARRAY <br />Array retrieved from the `REF_EXECUTE_TO_ARRAY`.<br />
	 * @return String[] <br />List of retrieved field names<br />
	 */
	Public Static Function REF_FIELD_NAME(Array $RESULT_ARRAY)
	{
		// Validate Parameter
		// ------------------------------------------------
		if(empty($RESULT_ARRAY) === True)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(New Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION("RESULT_ARRAY", False)));
		}
		// ------------------------------------------------
		
		
		// Actual Function
		// ------------------------------------------------
		Try
		{
			$FIELD_NAME = [];
			$KEY_INDEX = 0;
			
			// 2D Array
			// .........................................................
			if(isset($RESULT_ARRAY[0]))
			{
				$KEY_COLLECTION = array_keys($RESULT_ARRAY[0]);
				while(Count($KEY_COLLECTION) > $KEY_INDEX)
				{
					if(PHPVC_NUM::VAR_IS_NUMERIC($KEY_COLLECTION[$KEY_INDEX]) === False)
					{
						Array_Push($FIELD_NAME, $KEY_COLLECTION[$KEY_INDEX]);
					}
					$KEY_INDEX += 1; // Skip numerical indexes
				}
			}
			
			// 1D Array
			// .........................................................
			$KEY_COLLECTION = array_keys($RESULT_ARRAY);
			$KEY_INDEX = 0;
			while(Count($KEY_COLLECTION) > $KEY_INDEX)
			{
				if(PHPVC_NUM::VAR_IS_NUMERIC($KEY_COLLECTION[$KEY_INDEX]) === False)
				{
					Array_Push($FIELD_NAME, $KEY_COLLECTION[$KEY_INDEX]);
				}
				$KEY_INDEX += 1; // Skip numerical indexes
			}
			
			Return $FIELD_NAME;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// ------------------------------------------------
	}
}



Class PHPRC_PDO_MYSQL_PARAM
{
	/**
	 * Creates PDO Statement (similar to SQLCommand)
	 * @param PDOHandle $PDO_HANDLE <br />PDOHandle connected to database.<br />
	 * @param String $QUERY_TEXT<br />A query string. e.g. INSERT INTO REGISTRY(name, value) VALUES(:name, :value).<br />
	 * @return none
	 */
	Public Static Function REF_PREPARE($PDO_HANDLE, $QUERY_STRING)
	{
		// Validate Parameter
		// --------------------------------------
		If($PDO_HANDLE == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_HANDLE', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			Return $PDO_HANDLE->prepare($QUERY_STRING);
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Add value to statement
	 * @param PDOStatement $PDO_STATEMENT <br />Prepared PDO Statement.<br />
	 * @param String $PARAM_NAME <br />Parameter name. e.g. :name.<br />
	 * @param String $PARAM_VALUE <br />Parameter value to add (bind).<br />
	 * @param PDOParamType $PARAM_TYPE <br />PDO::PARAM types.<br />
	 * @return none
	 */
	Public Static Function REF_ADD($PDO_STATEMENT, $PARAM_NAME, $PARAM_VALUE, $PARAM_TYPE)
	{
		// Validate Parameter
		// --------------------------------------
		if($PDO_STATEMENT == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_STATEMENT', FALSE)));
		}
		if(PHPVC_STR::VAR_IS_BLANK($PARAM_NAME) === True)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_ARGUMENT_EXCEPTION_NULL('PARAM_NAME', FALSE)));
		}
		if(SELF::VAR_TYPE_IS_VALID($PARAM_TYPE) === False)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_ARGUMENT_EXCEPTION_UNSUPPORTED_TYPE('PARAM_TYPE', FALSE)));
		}
		// --------------------------------------
		
		
		// Actual Function
		// --------------------------------------
		Try
		{
			// Add (:) if not added before the parameter name
			if(PHPVC_STR::VAR_LEFT($PARAM_NAME, 1) <> ":")
			{
				$PARAM_NAME = ':' . $PARAM_NAME;
			}
			
			// If input is datetime, convert to String
			if(PHPVC_DATETIME::VAR_IS_DATETIME($PARAM_VALUE))
			{
				$PARAM_VALUE = PHPVC_DATETIME::VAR_TO_STRING($PARAM_VALUE);
			}
			
			// Bind Value
			if
			(
					isset($PARAM_VALUE) === false ||
					(
							$PARAM_TYPE == PDO::PARAM_STR &&
							$PARAM_VALUE <= PHPRC_SQL_FLAGS::FLAG_DECIMAL_NULL
							)
					)
			{
				// Handle NULLs (especially the decimal, where NULL value differes with scale)
				$PDO_STATEMENT->BindValue($PARAM_NAME, null, PDO::PARAM_INT);
			}
			else
			{
				$PDO_STATEMENT->BindValue($PARAM_NAME, $PARAM_VALUE, $PARAM_TYPE);
			}
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Checks if the PDO parameter type is valid or not
	 * @param PDOParamType $PDO_DB_TYPE <br />PDO Parameter type.<br />
	 * @return none
	 */
	Public Static Function VAR_TYPE_IS_VALID($PDO_DB_TYPE)
	{
		// Actual Function
		// --------------------------------------
		Try
		{
			If
			(
					PDO::PARAM_BOOL == $PDO_DB_TYPE ||
					PDO::PARAM_INT == $PDO_DB_TYPE ||
					PDO::PARAM_NULL == $PDO_DB_TYPE ||
					PDO::PARAM_STR == $PDO_DB_TYPE
					)
			{
				Return True;
			}
			Else
			{
				Return False;
			}
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			Throw $PDO_ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
	
	
	/**
	 * Log PDO Statement details into Log file.
	 * @param PDOStatement $PDO_STATEMENT <br />Prepared PDO Statement.<br />
	 * @return none
	 */
	Public Static Function VAR_LOG_DETAILS($PDO_STATEMENT)
	{
		// Validate Parameter
		// --------------------------------------
		If($PDO_STATEMENT == NULL)
		{
			Throw PHPVC_ERROR::VAR_RAISERROR(new Exception(PHPVC_ERROR::VAR_NULL_REFERENCE_EXCEPTION('PDO_STATEMENT', FALSE)));
		}
		// --------------------------------------
		
		// Actual Function
		// --------------------------------------
		Try
		{
			Ob_Start();
			$PDO_STATEMENT->DebugDumpParams();
			$LOG_DETAILS = Ob_Get_Contents();
			Ob_End_Clean();
			
			PHPVC_LOG::VAR_COMMENTS("PDO Statement", $LOG_DETAILS);
		}
		Catch(PDOException $PDO_ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($PDO_ERR, 0);
			Throw $ERR;
		}
		Catch(Exception $ERR)
		{
			PHPVC_LOG::VAR_REPORT_ERROR($ERR, 0);
			Throw $ERR;
		}
		// --------------------------------------
	}
}

?>