![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
King of Portal
|
An Attempt at a DBMS
My current project which is my forum software board uses a flat file database in order to store the forum's data (user data, post data, etc.). I grew curious and starting wondering how actual databases work, and realized that the grimBase class I created is a sort of pseudo-relational database. However, what I always seem to read is that irrelevant of the database, data is stored in tables in a column and row format of some sort. I don't know how the actual implementations go, but I wanted to address a problem in my implementation. I would imagine this falls under the category of creating locks for a database. So here's the code for the grimBase class.[PHP]<?php
echo '<pre>'; $blah = new grimBase('foo.php'); $blah->generateGlyph(array(0, 1, 2, 3, 4)); print_r($blah->parseGlyph()); echo '</pre>'; class grimBase{ var $gbArtefact; var $gbTablet; var $gbGlyph; var $gbArtefactExists = false; var $gbIsTablet = false; var $gbGlyphData = null; function grimBase($artefactID){ if(!isset($artefactID)) trigger_error("grimBase ( string filename) → Undefined argument filename", E_USER_ERROR); if(!is_string($artefactID)) trigger_error("grimBase ( string filename) → filename is an incorrect type", E_USER_ERROR); if(strlen($artefactID) == 0) trigger_error("grimBase ( string filename) → filename cannot be an empty string", E_USER_ERROR); $slashPos = strpos($artefactID, '/'); if($slashPos === 0 || $slashPos === strlen($artefactID) - 1) trigger_error("grimBase ( string filename) → filename cannot start with a / or end with a /", E_USER_ERROR); $this->gbArtefact = $artefactID; $this->gbArtefactExists = file_exists($this->gbArtefact); $this->gbIsTablet = is_dir($artefactID); $gbTemp = explode('/', $artefactID); $dotPos = strpos(end($gbTemp), '.'); if($dotPos !== false && $dotPos !== strlen(current($gbTemp)) - 1){ $this->gbGlyph = array_pop($gbTemp); }else{ $this->gbGlyph = ''; } if(count($gbTemp) > 1){ $this->gbTablet = implode('/', $gbTemp); }else{ $this->gbTablet = reset($gbTemp); } } function artefact(){ return $this->gbArtefact; } function tablet(){ return $this->gbTablet; } function glyph(){ return $this->gbGlyph; } function artefactExists(){ return $this->gbArtefactExists; } function artefactCount(){ if(!$this->gbArtefactExists) return !trigger_error("int grimBase->artefactCount ( void) → Tablet does not exist", E_USER_ERROR); return count($this->getArtefacts()); } function getArtefacts(){ if(!$this->gbArtefactExists) return !trigger_error("array grimBase->getArtefacts ( void) → Tablet does not exist", E_USER_ERROR); $far = array(); if($handle = opendir($this->gbTablet)){ while(false !== ($file = readdir($handle))){ if($file != "." && $file != ".."){ array_push($far, $file); } } closedir($handle); } return $far; } function generateTablet(){ if(file_exists($this->gbTablet)) return true; if(fluctuate($this->gbTablet, 0777)){ $this->gbArtefactExists = true; } return $this->gbArtefactExists; } function generateGlyph($glyphData){ if(!isset($glyphData)) return !trigger_error("bool grimBase->generateGlyph ( array &array) → Undefined argument &array", E_USER_ERROR); if(!is_array($glyphData)) return !trigger_error("bool grimBase->generateGlyph ( array &array) → &array is an incorrect type", E_USER_ERROR); if(count($glyphData) == 0) return !trigger_error("bool grimBase->generateGlyph ( array &array) → &array is empty", E_USER_ERROR); $this->gbGlyphData = $glyphData; $fout = '<?php /*' . chr(30); foreach($glyphData as $glyphKey => $glyphValue){ $fout .= $glyphKey; $fout .= ' = '; $fout .= serialize($glyphValue); $fout .= chr(30); } $fout .= '*/ ?>'; if(fluctuate($this->gbArtefact, 'w', $fout, 0777)){ $this->gbArtefactExists = true; $this->gbIsTablet = false; $this->gbGlyphData = $glyphData; return true; }else{ $this->gbArtefactExists = false; $this->gbGlyphData = null; return false; } } function scanGlyph($glyphID){ if(!$this->gbArtefactExists) return !trigger_error("mixed grimBase->scanGlyph ( string arrayKey) → Glyph does not exist", E_USER_ERROR); if($this->gbIsTablet) return !trigger_error("mixed grimBase->scanGlyph ( string arrayKey) → Cannot parse a tablet", E_USER_ERROR); if(!isset($this->gbGlyphData)){ $this->gbGlyphData = $this->parseGlyph(); } return $this->gbGlyphData[$glyphID]; } function parseGlyph(){ if(!$this->gbArtefactExists) return !trigger_error("array grimBase->parseGlyph ( void) → Glyph does not exist", E_USER_ERROR); if($this->gbIsTablet) return !trigger_error("array grimBase->parseGlyph ( void) → Cannot parse a tablet", E_USER_ERROR); $parseContent = file_get_contents($this->gbArtefact); if(false === $parseContent) return !trigger_error("array grimBase->parseGlyph ( void) → Unable to retrieve glyph contents", E_USER_ERROR); $contentParser = explode(chr(30), $parseContent); $parseContent = array(); array_shift($contentParser); array_pop($contentParser); reset($contentParser); foreach($contentParser as $contentValue){ $ePos = strpos($contentValue, '='); $parseKey = trim(substr($contentValue, 0, $ePos - 1)); $parseValue = unserialize(substr($contentValue, $ePos + 2)); $parseContent[$parseKey] = $parseValue; } $this->gbGlyphData = $parseContent; return $parseContent; } } function fluctuate(){ $args = func_get_args(); switch(func_num_args()){ case 1: if(!is_string($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → <em>filename</em> is not a string", E_USER_ERROR); if(is_file($args[0])){ if(unlink($args[0])) return true; else return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to delete file", E_USER_WARNING); }elseif(is_dir($args[0])){ if(rmdir($args[0])) return true; else return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to delete folder", E_USER_WARNING); }else return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Nonexistent file/directory cannot be deleted", E_USER_NOTICE); case 2: if(!is_string($args[0])) return !trigger_error("bool fluctuate ( string dirname [, int mode]) → <em>filename</em> is not a string", E_USER_ERROR); if(!is_int($args[1])) return !trigger_error("bool fluctuate ( string dirname [, int mode]) → <em>mode</em> is not an int", E_USER_ERROR); if(mkdir($args[0], $args[1])){ return true; }else{ return !trigger_error("bool fluctuate ( string dirname [, int mode]) → Unable to create directory", E_USER_ERROR); } case 4: if(!is_string($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → <em>filename</em> is not a string", E_USER_ERROR); if(!is_string($args[1]) || strlen($args[1]) !== 1) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → <em>mode</em> is not a character", E_USER_ERROR); if(!is_int($args[3])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → <em>mode</em> is not an int", E_USER_ERROR); $args[1] = strtolower($args[1]); $ffd = null; switch($args[1]){ case 'a': if(!file_exists($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Cannot append to nonexistent file", E_USER_WARNING); if(!is_writeable($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → File is not writeable", E_USER_WARNING); if(false === ($ffd = fopen($args[0], "a"))) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to open file", E_USER_WARNING); break; case 'w': if(false === ($ffd = fopen($args[0], "w"))) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to open file", E_USER_WARNING); if(!file_exists($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Cannot write to nonexistent file", E_USER_WARNING); if(!is_writeable($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → File is not writeable", E_USER_WARNING); break; default: return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Illegal mode specified", E_USER_ERROR); } if(stream_set_write_buffer($ffd, 0) !== -1) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to buffer stream", E_USER_WARNING); if(fwrite($ffd, $args[2]) === false) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to write to file", E_USER_WARNING); if(!fclose($ffd)) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to close file", E_USER_WARNING); if(!chmod($args[0], $args[3])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Unable to change file permissions", E_USER_WARNING); return true; default: return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) → Incorrect quantity of arguments supplied", E_USER_ERROR); } } ?>[/PHP]Now to compare actual database tables to my own there's 3 things to know about the grimBase class. It is composed of what I call Artefacts, Tablets, and Glyphs. Tablets and Glyphs are both Artefacts. On your local computer Tablets are the equivalent of folders/directories and Glyphs are ascii text files. So for instance when I want to create a database table (what I call a Tablet) I would code something like $foo = new grimBase('foo');
$foo->generateTablet();$foo = new grimBase('foo/0.php');
$foo->generateGlyph(array(0, 1, 2, 3, 4));
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis Last edited by grimpirate; Apr 16th, 2007 at 11:19 PM. |
|
|
|
|
|
#2 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
There's nothing wrong with experimenting around, in the dark, in an attempt to invent databases. I would suggest that you would be well ahead of the game if you learned how current databases work and experimented around, in the light, in an attempt to improve on them. Just personal opinion.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#3 |
|
King of Portal
|
I agree DaWei, I'm not trying to reinvent the wheel or anything. I'm reading the book Database Management Systems 2nd Ed. from McGraw Hill. It talks about a great deal of things that I can't really seem to find much info about online. Usually all I manage to end up googling is someone explaining SQL or how SQL works to get stuff done, how the tables look, etc. It's all very kind of separated from the code that creates the database. There's sqllite, but that's written in C and my grasp of C is limited. Furthermore, I'm pretty weak at reading other's code. I'm not actually trying to improve databases. It's just that I use free webservers so it would be nice to have one that's free. There's one that I found which is txtSQL which I have yet to look into further, but it's always very difficult to study someone else's code if it isn't explained entirely.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis |
|
|
|
|
|
#4 | |
|
Professional Programmer
Join Date: May 2006
Location: UK - London
Posts: 330
Rep Power: 3
![]() |
What you need to do is find out the functions of a DBMS, for example:
Store, retrieve and update data Transaction Services Data-independence Data integrity service Security service Concurrency control service Data Communication Service Recovery and Backup services Also I think there is something called the ANSI-SPARC Three Layer Model that you can follow to help with the design and hopefully the implementation of your DBMS
__________________
Quote:
|
|
|
|
|
|
|
#5 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
If you have a machine at home, I'd recommend you put an AMP package on it and play with that. Then you'll know how to use a DB if/when you have a host that supports it.
Writing a DB has two aspects. One is the functionality. You can learn to write that in any language, but the end result will likely be missing the other aspect: performance. Performance is attained by writing code that is very system specific, close to the machine.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#6 | |
|
Programming Guru
![]() ![]() ![]() |
Quote:
Kudos on your effort. Makes me want to write a web application in PHP now.
__________________
http://jasonpowers.net "There are a thousand hacking at the branches of evil to one who is striking at the root." |
|
|
|
|
|
|
#7 |
|
King of Portal
|
@kruptof: Hmm... browsed around for ANSI - SPARC but I mostly find cryptic definitions. All those concepts you mention are addressed in the book I'm reading, along with ACID and many others.
@DaWei: When I search for AMP package on Google all I get are like actual guitar amps lol, sorry I don't know what the acronym stands for. I've already worked with databases and understand how to use the SQL language and such. However, that's very separated from the actual physical things going on in a database,and of course performance is undoubtedly a crucial feature of a database. However, due to my free webhost constraint performance is secondary. I would venture to hypothesize that perhaps using the PHP filesystem functions and the like might be quicker than actually logging into the database and polling it over and over, at least online that is. @Infinite Recursion: lol yeah I know that MySQL is free and open source, that isn't what I mean though. Your host still has to grant you database access to use MySQL, and a lot of free webhosts don't. Happy I could get you motivated ^_^ How about a mod for GrimBB? SHAMELESS PLUG! lol @anyone still reading: I did find this other pretty impressive flat file database http://gladius.sourceforge.net/. That's pretty much what I'm trying to create. However, looking at their source code gives me a headache *_* lol Obviously those people know what they're doing as I ignorantly assume good code gives me a headache. Regarding the problem that I was stating earlier I think I may have come up with a solution. When a user decides to make a post I should immediately create a Glyph which indicates that someone is accessing the Tablet in order to create a post. Perhaps this Glyph could contain a queue of sorts, so as to process each user's post systematically. I assume that if the same thing where to happen here on PFO the thread wouldn't update dynamically if a post was made right now while I'm typing this one.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis |
|
|
|
|
|
#8 | |
|
Professional Programmer
Join Date: May 2006
Location: UK - London
Posts: 330
Rep Power: 3
![]() |
here is what i think Dawei meant http://www.wampserver.com/en/, good for practising and testing your project on.
__________________
Quote:
|
|
|
|
|
|
|
#9 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
AMP is Apache/MySql/PHP. It's a very easy thing to implement. You can also find binary packages the do the entire installation, but I don't like them as well.
This kind of setup allows you to play on your home machine, regardless of what your host provides. You can also add things like Perl to the mix.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Connection attempt | zorin | Coder's Corner Lounge | 11 | Sep 15th, 2005 1:55 PM |
| Add DBMS section | codetaino | Community Announcements and Feedback | 4 | Jan 15th, 2005 1:25 PM |