Ejemplo n.º 1
0
/*
** The next group of routines are convenience wrappers around the
** VFS methods.
*/
UNQLITE_PRIVATE int unqliteOsOpen(
  unqlite_vfs *pVfs,
  SyMemBackend *pAlloc,
  const char *zPath, 
  unqlite_file **ppOut, 
  unsigned int flags 
)
{
	unqlite_file *pFile;
	int rc;
	*ppOut = 0;
	if( zPath == 0 ){
		/* May happen if dealing with an in-memory database */
		return SXERR_EMPTY;
	}
	/* Allocate a new instance */
	pFile = (unqlite_file *)SyMemBackendAlloc(pAlloc,sizeof(unqlite_file)+pVfs->szOsFile);
	if( pFile == 0 ){
		return UNQLITE_NOMEM;
	}
	/* Zero the structure */
	SyZero(pFile,sizeof(unqlite_file)+pVfs->szOsFile);
	/* Invoke the xOpen method of the underlying VFS */
	rc = pVfs->xOpen(pVfs, zPath, pFile, flags);
	if( rc != UNQLITE_OK ){
		SyMemBackendFree(pAlloc,pFile);
		pFile = 0;
	}
	*ppOut = pFile;
	return rc;
}
Ejemplo n.º 2
0
/*
 * Install a freshly created collection in the unqlite VM.
 */
static int unqliteVmInstallCollection(
	unqlite_vm *pVm,  /* Target VM */
	unqlite_col *pCol /* Collection to install */
	)
{
	SyString *pName = &pCol->sName;
	sxu32 iBucket;
	/* Hash the collection name */
	pCol->nHash = SyBinHash((const void *)pName->zString,pName->nByte);
	/* Install it in the corresponding bucket */
	iBucket = pCol->nHash & (pVm->iColSize - 1);
	pCol->pNextCol = pVm->apCol[iBucket];
	if( pVm->apCol[iBucket] ){
		pVm->apCol[iBucket]->pPrevCol = pCol;
	}
	pVm->apCol[iBucket] = pCol;
	/* Link to the list of active collections */
	MACRO_LD_PUSH(pVm->pCol,pCol);
	pVm->iCol++;
	if( (pVm->iCol >= pVm->iColSize * 4) && pVm->iCol < 10000 ){
		/* Grow the hashtable */
		sxu32 nNewSize = pVm->iColSize << 1;
		unqlite_col *pEntry;
		unqlite_col **apNew;
		sxu32 n;
		
		apNew = (unqlite_col **)SyMemBackendAlloc(&pVm->sAlloc, nNewSize * sizeof(unqlite_col *));
		if( apNew ){
			/* Zero the new table */
			SyZero((void *)apNew, nNewSize * sizeof(unqlite_col *));
			/* Rehash all entries */
			n = 0;
			pEntry = pVm->pCol;
			for(;;){
				/* Loop one */
				if( n >= pVm->iCol ){
					break;
				}
				pEntry->pNextCol = pEntry->pPrevCol = 0;
				/* Install in the new bucket */
				iBucket = pEntry->nHash & (nNewSize - 1);
				pEntry->pNextCol = apNew[iBucket];
				if( apNew[iBucket]  ){
					apNew[iBucket]->pPrevCol = pEntry;
				}
				apNew[iBucket] = pEntry;
				/* Point to the next entry */
				pEntry = pEntry->pNext;
				n++;
			}
			/* Release the old table and reflect the change */
			SyMemBackendFree(&pVm->sAlloc,(void *)pVm->apCol);
			pVm->apCol = apNew;
			pVm->iColSize  = nNewSize;
		}
	}
	return UNQLITE_OK;
}
Ejemplo n.º 3
0
/*
 * Initialize a jx9_value to the null type.
 */
JX9_PRIVATE sxi32 jx9MemObjInit(jx9_vm *pVm, jx9_value *pObj)
{
	/* Zero the structure */
	SyZero(pObj, sizeof(jx9_value));
	/* Initialize fields */
	pObj->pVm = pVm;
	SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
	/* Set the NULL type */
	pObj->iFlags = MEMOBJ_NULL;
	return SXRET_OK;
}
Ejemplo n.º 4
0
/*
 * Initialize a jx9_value to the array type.
 */
JX9_PRIVATE sxi32 jx9MemObjInitFromArray(jx9_vm *pVm, jx9_value *pObj, jx9_hashmap *pArray)
{
	/* Zero the structure */
	SyZero(pObj, sizeof(jx9_value));
	/* Initialize fields */
	pObj->pVm = pVm;
	SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
	/* Set the desired type */
	pObj->iFlags = MEMOBJ_HASHMAP;
	pObj->x.pOther = pArray;
	return SXRET_OK;
}
Ejemplo n.º 5
0
/*
 * Initialize a jx9_value to the real type.
 */
JX9_PRIVATE sxi32 jx9MemObjInitFromReal(jx9_vm *pVm, jx9_value *pObj, jx9_real rVal)
{
	/* Zero the structure */
	SyZero(pObj, sizeof(jx9_value));
	/* Initialize fields */
	pObj->pVm = pVm;
	SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
	/* Set the desired type */
	pObj->x.rVal = rVal;
	pObj->iFlags = MEMOBJ_REAL;
	return SXRET_OK;
}
Ejemplo n.º 6
0
/*
 * Initialize a jx9_value to the string type.
 */
JX9_PRIVATE sxi32 jx9MemObjInitFromString(jx9_vm *pVm, jx9_value *pObj, const SyString *pVal)
{
	/* Zero the structure */
	SyZero(pObj, sizeof(jx9_value));
	/* Initialize fields */
	pObj->pVm = pVm;
	SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
	if( pVal ){
		/* Append contents */
		SyBlobAppend(&pObj->sBlob, (const void *)pVal->zString, pVal->nByte);
	}
	/* Set the desired type */
	pObj->iFlags = MEMOBJ_STRING;
	return SXRET_OK;
}
Ejemplo n.º 7
0
/*
 * Install a freshly created record in a given collection. 
 */
static int CollectionCacheInstallRecord(
	unqlite_col *pCol, /* Target collection */
	jx9_int64 nId,     /* Unique record ID */
	jx9_value *pValue  /* JSON value */
	)
{
	unqlite_col_record *pRecord;
	sxu32 iBucket;
	/* Fetch the record first */
	pRecord = CollectionCacheFetchRecord(pCol,nId);
	if( pRecord ){
		/* Record already installed, overwrite its old value  */
		jx9MemObjStore(pValue,&pRecord->sValue);
		return UNQLITE_OK;
	}
	/* Allocate a new instance */
	pRecord = (unqlite_col_record *)SyMemBackendPoolAlloc(&pCol->pVm->sAlloc,sizeof(unqlite_col_record));
	if( pRecord == 0 ){
		return UNQLITE_NOMEM;
	}
	/* Zero the structure */
	SyZero(pRecord,sizeof(unqlite_col_record));
	/* Fill in the structure */
	jx9MemObjInit(pCol->pVm->pJx9Vm,&pRecord->sValue);
	jx9MemObjStore(pValue,&pRecord->sValue);
	pRecord->nId = nId;
	pRecord->pCol = pCol;
	/* Install in the corresponding bucket */
	iBucket = COL_RECORD_HASH(nId) & (pCol->nRecSize - 1);
	pRecord->pNextCol = pCol->apRecord[iBucket];
	if( pCol->apRecord[iBucket] ){
		pCol->apRecord[iBucket]->pPrevCol = pRecord;
	}
	pCol->apRecord[iBucket] = pRecord;
	/* Link */
	MACRO_LD_PUSH(pCol->pList,pRecord);
	pCol->nRec++;
	if( (pCol->nRec >= pCol->nRecSize * 3) && pCol->nRec < 100000 ){
		/* Allocate a new larger table */
		sxu32 nNewSize = pCol->nRecSize << 1;
		unqlite_col_record *pEntry;
		unqlite_col_record **apNew;
		sxu32 n;
		
		apNew = (unqlite_col_record **)SyMemBackendAlloc(&pCol->pVm->sAlloc, nNewSize * sizeof(unqlite_col_record *));
		if( apNew ){
			/* Zero the new table */
			SyZero((void *)apNew, nNewSize * sizeof(unqlite_col_record *));
			/* Rehash all entries */
			n = 0;
			pEntry = pCol->pList;
			for(;;){
				/* Loop one */
				if( n >= pCol->nRec ){
					break;
				}
				pEntry->pNextCol = pEntry->pPrevCol = 0;
				/* Install in the new bucket */
				iBucket = COL_RECORD_HASH(pEntry->nId) & (nNewSize - 1);
				pEntry->pNextCol = apNew[iBucket];
				if( apNew[iBucket]  ){
					apNew[iBucket]->pPrevCol = pEntry;
				}
				apNew[iBucket] = pEntry;
				/* Point to the next entry */
				pEntry = pEntry->pNext;
				n++;
			}
			/* Release the old table and reflect the change */
			SyMemBackendFree(&pCol->pVm->sAlloc,(void *)pCol->apRecord);
			pCol->apRecord = apNew;
			pCol->nRecSize = nNewSize;
		}
	}
	/* All done */
	return UNQLITE_OK;
}
Ejemplo n.º 8
0
/*
 * Load or create a binary collection.
 */
static int unqliteVmLoadCollection(
	unqlite_vm *pVm,    /* Target VM */
	const char *zName,  /* Collection name */
	sxu32 nByte,        /* zName length */
	int iFlag,          /* Control flag */
	unqlite_col **ppOut /* OUT: in-memory collection */
	)
{
	unqlite_kv_methods *pMethods;
	unqlite_kv_engine *pEngine;
	unqlite_kv_cursor *pCursor;
	unqlite *pDb = pVm->pDb;
	unqlite_col *pCol = 0; /* cc warning */
	int rc = SXERR_MEM;
	char *zDup = 0;
	/* Point to the underlying KV store */
	pEngine = unqlitePagerGetKvEngine(pVm->pDb);
	pMethods = pEngine->pIo->pMethods;
	/* Allocate a new cursor */
	rc = unqliteInitCursor(pDb,&pCursor);
	if( rc != UNQLITE_OK ){
		return rc;
	}
	if( (iFlag & UNQLITE_VM_COLLECTION_CREATE) == 0 ){
		/* Seek to the desired location */
		rc = pMethods->xSeek(pCursor,(const void *)zName,(unqlite_int64)nByte,UNQLITE_CURSOR_MATCH_EXACT);
		if( rc != UNQLITE_OK ){
			unqliteGenErrorFormat(pDb,"Collection '%.*s' not defined in the underlying database",nByte,zName);
			unqliteReleaseCursor(pDb,pCursor);
			return rc;
		}
	}
	/* Allocate a new instance */
	pCol = (unqlite_col *)SyMemBackendPoolAlloc(&pVm->sAlloc,sizeof(unqlite_col));
	if( pCol == 0 ){
		unqliteGenOutofMem(pDb);
		rc = UNQLITE_NOMEM;
		goto fail;
	}
	SyZero(pCol,sizeof(unqlite_col));
	/* Fill in the structure */
	SyBlobInit(&pCol->sWorker,&pVm->sAlloc);
	SyBlobInit(&pCol->sHeader,&pVm->sAlloc);
	pCol->pVm = pVm;
	pCol->pCursor = pCursor;
	/* Duplicate collection name */
	zDup = SyMemBackendStrDup(&pVm->sAlloc,zName,nByte);
	if( zDup == 0 ){
		unqliteGenOutofMem(pDb);
		rc = UNQLITE_NOMEM;
		goto fail;
	}
	pCol->nRecSize = 64; /* Must be a power of two */
	pCol->apRecord = (unqlite_col_record **)SyMemBackendAlloc(&pVm->sAlloc,pCol->nRecSize * sizeof(unqlite_col_record *));
	if( pCol->apRecord == 0 ){
		unqliteGenOutofMem(pDb);
		rc = UNQLITE_NOMEM;
		goto fail;
	}
	/* Zero the table */
	SyZero((void *)pCol->apRecord,pCol->nRecSize * sizeof(unqlite_col_record *));
	SyStringInitFromBuf(&pCol->sName,zDup,nByte);
	jx9MemObjInit(pVm->pJx9Vm,&pCol->sSchema);
	if( iFlag & UNQLITE_VM_COLLECTION_CREATE ){
		/* Create a new collection */
		if( pMethods->xReplace == 0 ){
			/* Read-only KV engine: Generate an error message and return */
			unqliteGenErrorFormat(pDb,
				"Cannot create new collection '%z' due to a read-only Key/Value storage engine",
				&pCol->sName
			);
			rc = UNQLITE_ABORT; /* Abort VM execution */
			goto fail;
		}
		/* Write the collection header */
		rc = CollectionSetHeader(pEngine,pCol,0,0,0);
		if( rc != UNQLITE_OK ){
			rc = UNQLITE_ABORT; /* Abort VM execution */
			goto fail;
		}
	}else{
		/* Read the collection header */
		rc = CollectionLoadHeader(pCol);
		if( rc != UNQLITE_OK ){
			unqliteGenErrorFormat(pDb,"Corrupt collection '%z' header",&pCol->sName);
			goto fail;
		}
	}
	/* Finally install the collection */
	unqliteVmInstallCollection(pVm,pCol);
	/* All done */
	if( ppOut ){
		*ppOut = pCol;
	}
	return UNQLITE_OK;
fail:
	unqliteReleaseCursor(pDb,pCursor);
	if( zDup ){
		SyMemBackendFree(&pVm->sAlloc,zDup);
	}
	if( pCol ){
		if( pCol->apRecord ){
			SyMemBackendFree(&pVm->sAlloc,(void *)pCol->apRecord);
		}
		SyBlobRelease(&pCol->sHeader);
		SyBlobRelease(&pCol->sWorker);
		jx9MemObjRelease(&pCol->sSchema);
		SyMemBackendPoolFree(&pVm->sAlloc,pCol);
	}
	return rc;
}
Ejemplo n.º 9
0
/*
 * Write and/or alter collection binary header.
 */
static int CollectionSetHeader(
	unqlite_kv_engine *pEngine, /* Underlying KV storage engine */
	unqlite_col *pCol,          /* Target collection */
	jx9_int64 iRec,             /* Last record ID */
	jx9_int64 iTotal,           /* Total number of records in this collection */
	jx9_value *pSchema          /* Collection schema */
	)
{
	SyBlob *pHeader = &pCol->sHeader;
	unqlite_kv_methods *pMethods;
	int iWrite = 0;
	int rc;
	if( pEngine == 0 ){
		/* Default storage engine */
		pEngine = unqlitePagerGetKvEngine(pCol->pVm->pDb);
	}
	pMethods = pEngine->pIo->pMethods;
	if( SyBlobLength(pHeader) < 1 ){
		Sytm *pCreate = &pCol->sCreation; /* Creation time */
		unqlite_vfs *pVfs;
		sxu32 iDos;
		/* Magic number */
		rc = SyBlobAppendBig16(pHeader,UNQLITE_COLLECTION_MAGIC);
		if( rc != UNQLITE_OK ){
			return rc;
		}
		/* Initial record ID */
		rc = SyBlobAppendBig64(pHeader,0);
		if( rc != UNQLITE_OK ){
			return rc;
		}
		/* Total records in the collection */
		rc = SyBlobAppendBig64(pHeader,0);
		if( rc != UNQLITE_OK ){
			return rc;
		}
		pVfs = (unqlite_vfs *)unqliteExportBuiltinVfs();
		/* Creation time of the collection */
		if( pVfs->xCurrentTime ){
			/* Get the creation time */
			pVfs->xCurrentTime(pVfs,pCreate);
		}else{
			/* Zero the structure */
			SyZero(pCreate,sizeof(Sytm));
		}
		/* Convert to DOS time */
		SyTimeFormatToDos(pCreate,&iDos);
		rc = SyBlobAppendBig32(pHeader,iDos);
		if( rc != UNQLITE_OK ){
			return rc;
		}
		/* Offset to start writing collection schema */
		pCol->nSchemaOfft = SyBlobLength(pHeader);
		iWrite = 1;
	}else{
		unsigned char *zBinary = (unsigned char *)SyBlobData(pHeader);
		/* Header update */
		if( iRec >= 0 ){
			/* Update record ID */
			SyBigEndianPack64(&zBinary[2/* Magic number*/],(sxu64)iRec);
			iWrite = 1;
		}
		if( iTotal >= 0 ){
			/* Total records */
			SyBigEndianPack64(&zBinary[2/* Magic number*/+8/* Record ID*/],(sxu64)iTotal);
			iWrite = 1;
		}
		if( pSchema ){
			/* Collection Schema */
			SyBlobTruncate(pHeader,pCol->nSchemaOfft);
			/* Encode the schema to FastJson */
			rc = FastJsonEncode(pSchema,pHeader,0);
			if( rc != UNQLITE_OK ){
				return rc;
			}
			/* Copy the collection schema */
			jx9MemObjStore(pSchema,&pCol->sSchema);
			iWrite = 1;
		}
	}
	if( iWrite ){
		SyString *pId = &pCol->sName;
		/* Reflect the disk and/or in-memory image */
		rc = pMethods->xReplace(pEngine,
			(const void *)pId->zString,pId->nByte,
			SyBlobData(pHeader),SyBlobLength(pHeader)
			);
		if( rc != UNQLITE_OK ){
			unqliteGenErrorFormat(pCol->pVm->pDb,
				"Cannot save collection '%z' header in the underlying storage engine",
				pId
				);
			return rc;
		}
	}
	return UNQLITE_OK;
}
Ejemplo n.º 10
0
/*
 * Extract a single expression node from the input.
 * On success store the freshly extractd node in ppNode.
 * When errors, JX9 take care of generating the appropriate error message.
 * An expression node can be a variable [i.e: $var], an operator [i.e: ++] 
 * an annonymous function [i.e: function(){ return "Hello"; }, a double/single
 * quoted string, a heredoc/nowdoc, a literal [i.e: JX9_EOL], a namespace path
 * [i.e: namespaces\path\to..], a array/list [i.e: array(4, 5, 6)] and so on.
 */
static sxi32 ExprExtractNode(jx9_gen_state *pGen, jx9_expr_node **ppNode)
{
	jx9_expr_node *pNode;
	SyToken *pCur;
	sxi32 rc;
	/* Allocate a new node */
	pNode = (jx9_expr_node *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(jx9_expr_node));
	if( pNode == 0 ){
		/* If the supplied memory subsystem is so sick that we are unable to allocate
		 * a tiny chunk of memory, there is no much we can do here.
		 */
		return SXERR_MEM;
	}
	/* Zero the structure */
	SyZero(pNode, sizeof(jx9_expr_node));
	SySetInit(&pNode->aNodeArgs, &pGen->pVm->sAllocator, sizeof(jx9_expr_node **));
	/* Point to the head of the token stream */
	pCur = pNode->pStart = pGen->pIn;
	/* Start collecting tokens */
	if( pCur->nType & JX9_TK_OP ){
		/* Point to the instance that describe this operator */
		pNode->pOp = (const jx9_expr_op *)pCur->pUserData;
		/* Advance the stream cursor */
		pCur++;
	}else if( pCur->nType & JX9_TK_DOLLAR ){
		/* Isolate variable */
		pCur++; /* Jump the dollar sign */
		if( pCur >= pGen->pEnd ){
			/* Syntax error */
			rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"Invalid variable name");
			if( rc != SXERR_ABORT ){
				rc = SXERR_SYNTAX;
			}
			SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
			return rc;
		}
		pCur++; /* Jump the variable name */
		pNode->xCode = jx9CompileVariable;
	}else if( pCur->nType & JX9_TK_OCB /* '{' */ ){
		/* JSON Object, assemble tokens */
		pCur++;
		jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_OCB /* '[' */, JX9_TK_CCB /* ']' */, &pCur);
		if( pCur < pGen->pEnd ){
			pCur++;
		}else{
			/* Syntax error */
			rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"JSON Object: Missing closing braces '}'");
			if( rc != SXERR_ABORT ){
				rc = SXERR_SYNTAX;
			}
			SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
			return rc;
		}
		pNode->xCode = jx9CompileJsonObject;
	}else if( pCur->nType & JX9_TK_OSB /* '[' */ && !(pCur->nType & JX9_TK_OP) ){
		/* JSON Array, assemble tokens */
		pCur++;
		jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_OSB /* '[' */, JX9_TK_CSB /* ']' */, &pCur);
		if( pCur < pGen->pEnd ){
			pCur++;
		}else{
			/* Syntax error */
			rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"JSON Array: Missing closing square bracket ']'");
			if( rc != SXERR_ABORT ){
				rc = SXERR_SYNTAX;
			}
			SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
			return rc;
		}
		pNode->xCode = jx9CompileJsonArray;
	}else if( pCur->nType & JX9_TK_KEYWORD ){
		 int nKeyword = SX_PTR_TO_INT(pCur->pUserData);
		 if( nKeyword == JX9_TKWRD_FUNCTION ){
			 /* Annonymous function */
			  if( &pCur[1] >= pGen->pEnd ){
				 /* Assume a literal */
				pCur++;
				pNode->xCode = jx9CompileLiteral;
			 }else{
				 /* Assemble annonymous functions body */
				 rc = ExprAssembleAnnon(&(*pGen), &pCur, pGen->pEnd);
				 if( rc != SXRET_OK ){
					 SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
					 return rc; 
				 }
				 pNode->xCode = jx9CompileAnnonFunc;
			  }
		 }else if( jx9IsLangConstruct(nKeyword) && &pCur[1] < pGen->pEnd ){
			 /* Language constructs [i.e: print,die...] require special handling */
			 jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_LPAREN|JX9_TK_OCB|JX9_TK_OSB, JX9_TK_RPAREN|JX9_TK_CCB|JX9_TK_CSB, &pCur);
			 pNode->xCode = jx9CompileLangConstruct;
		 }else{
			 /* Assume a literal */
			 pCur++;
			 pNode->xCode = jx9CompileLiteral;
		 }
	 }else if( pCur->nType & (JX9_TK_ID) ){
		 /* Constants, function name, namespace path, object name... */
		 pCur++;
		 pNode->xCode = jx9CompileLiteral;
	 }else{
		 if( (pCur->nType & (JX9_TK_LPAREN|JX9_TK_RPAREN|JX9_TK_COMMA|JX9_TK_CSB|JX9_TK_OCB|JX9_TK_CCB|JX9_TK_COLON)) == 0 ){
			 /* Point to the code generator routine */
			 pNode->xCode = jx9GetNodeHandler(pCur->nType);
			 if( pNode->xCode == 0 ){
				 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Syntax error: Unexpected token '%z'", &pNode->pStart->sData);
				 if( rc != SXERR_ABORT ){
					 rc = SXERR_SYNTAX;
				 }
				 SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
				 return rc;
			 }
		 }
		/* Advance the stream cursor */
		pCur++;
	 }
	/* Point to the end of the token stream */
	pNode->pEnd = pCur;
	/* Save the node for later processing */
	*ppNode = pNode;
	/* Synchronize cursors */
	pGen->pIn = pCur;
	return SXRET_OK;
}