Example #1
0
/*
 * Drop a collection from the KV storage engine and the underlying
 * unqlite VM.
 */
UNQLITE_PRIVATE int unqliteDropCollection(unqlite_col *pCol)
{
	unqlite_vm *pVm = pCol->pVm;
	jx9_int64 nId;
	int rc;
	/* Reset the cursor */
	unqlite_kv_cursor_reset(pCol->pCursor);
	/* Seek the cursor to the desired location */
	rc = unqlite_kv_cursor_seek(pCol->pCursor,
		SyStringData(&pCol->sName),SyStringLength(&pCol->sName),
		UNQLITE_CURSOR_MATCH_EXACT
		);
	if( rc == UNQLITE_OK ){
		/* Remove the record from the storage engine */
		rc = unqlite_kv_cursor_delete_entry(pCol->pCursor);
	}
	if( rc != UNQLITE_OK ){
		unqliteGenErrorFormat(pCol->pVm->pDb,
				"Cannot remove collection '%z' due to a read-only Key/Value storage engine",
				&pCol->sName
			);
		return rc;
	}
	/* Drop collection records */
	for( nId = 0 ; nId < pCol->nLastid ; ++nId ){
		unqliteCollectionDropRecord(pCol,nId,0,0);
	}
	/* Cleanup */
	CollectionCacheRelease(pCol);
	SyBlobRelease(&pCol->sHeader);
	SyBlobRelease(&pCol->sWorker);
	SyMemBackendFree(&pVm->sAlloc,(void *)SyStringData(&pCol->sName));
	unqliteReleaseCursor(pVm->pDb,pCol->pCursor);
	/* Unlink */
	if( pCol->pPrevCol ){
		pCol->pPrevCol->pNextCol = pCol->pNextCol;
	}else{
		sxu32 iBucket = pCol->nHash & (pVm->iColSize - 1);
		pVm->apCol[iBucket] = pCol->pNextCol;
	}
	if( pCol->pNextCol ){
		pCol->pNextCol->pPrevCol = pCol->pPrevCol;
	}
	MACRO_LD_REMOVE(pVm->pCol,pCol);
	pVm->iCol--;
	SyMemBackendPoolFree(&pVm->sAlloc,pCol);
	return UNQLITE_OK;
}
Example #2
0
/*
 * Duplicate the contents of a jx9_value.
 */
JX9_PRIVATE sxi32 jx9MemObjStore(jx9_value *pSrc, jx9_value *pDest)
{
	jx9_hashmap *pMap = 0;
	sxi32 rc;
	if( pSrc->iFlags & MEMOBJ_HASHMAP ){
		/* Increment reference count */
		((jx9_hashmap *)pSrc->x.pOther)->iRef++;
	}
	if( pDest->iFlags & MEMOBJ_HASHMAP ){
		pMap = (jx9_hashmap *)pDest->x.pOther;
	}
	SyMemcpy((const void *)&(*pSrc), &(*pDest), sizeof(jx9_value)-(sizeof(jx9_vm *)+sizeof(SyBlob)+sizeof(sxu32)));
	rc = SXRET_OK;
	if( SyBlobLength(&pSrc->sBlob) > 0 ){
		SyBlobReset(&pDest->sBlob);
		rc = SyBlobDup(&pSrc->sBlob, &pDest->sBlob);
	}else{
		if( SyBlobLength(&pDest->sBlob) > 0 ){
			SyBlobRelease(&pDest->sBlob);
		}
	}
	if( pMap ){
		jx9HashmapUnref(pMap);
	}
	return rc;
}
Example #3
0
/*
 * Convert a jx9_value to type array.Invalidate any prior representations.
  * According to the JX9 language reference manual.
  *   For any of the types: integer, float, string, boolean converting a value
  *   to an array results in an array with a single element with index zero 
  *   and the value of the scalar which was converted.
  */
JX9_PRIVATE sxi32 jx9MemObjToHashmap(jx9_value *pObj)
{
	if( (pObj->iFlags & MEMOBJ_HASHMAP) == 0 ){
		jx9_hashmap *pMap;
		/* Allocate a new hashmap instance */
		pMap = jx9NewHashmap(pObj->pVm, 0, 0);
		if( pMap == 0 ){
			return SXERR_MEM;
		}
		if( (pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_RES)) == 0 ){
			/* 
			 * According to the JX9 language reference manual.
			 *   For any of the types: integer, float, string, boolean converting a value
			 *   to an array results in an array with a single element with index zero 
			 *   and the value of the scalar which was converted.
			 */
			/* Insert a single element */
			jx9HashmapInsert(pMap, 0/* Automatic index assign */, &(*pObj));
			SyBlobRelease(&pObj->sBlob);
		}
		/* Invalidate any prior representation */
		MemObjSetType(pObj, MEMOBJ_HASHMAP);
		pObj->x.pOther = pMap;
	}
	return SXRET_OK;
}
Example #4
0
/*
 * Convert a jx9_value to type boolean.Invalidate any prior representations.
 */
JX9_PRIVATE sxi32 jx9MemObjToBool(jx9_value *pObj)
{
	if( (pObj->iFlags & MEMOBJ_BOOL) == 0 ){
		/* Preform the conversion */
		pObj->x.iVal = MemObjBooleanValue(&(*pObj));
		/* Invalidate any prior representations */
		SyBlobRelease(&pObj->sBlob);
		MemObjSetType(pObj, MEMOBJ_BOOL);
	}
	return SXRET_OK;
}
Example #5
0
/*
 * Invalidate any prior representation of a given jx9_value.
 */
JX9_PRIVATE sxi32 jx9MemObjRelease(jx9_value *pObj)
{
	if( (pObj->iFlags & MEMOBJ_NULL) == 0 ){
		if( pObj->iFlags & MEMOBJ_HASHMAP ){
			jx9HashmapUnref((jx9_hashmap *)pObj->x.pOther);
		}
		/* Release the internal buffer */
		SyBlobRelease(&pObj->sBlob);
		/* Invalidate any prior representation */
		pObj->iFlags = MEMOBJ_NULL;
	}
	return SXRET_OK;
}
Example #6
0
/*
 * Duplicate the contents of a jx9_value but do not copy internal
 * buffer contents, simply point to it.
 */
JX9_PRIVATE sxi32 jx9MemObjLoad(jx9_value *pSrc, jx9_value *pDest)
{
	SyMemcpy((const void *)&(*pSrc), &(*pDest), 
		sizeof(jx9_value)-(sizeof(jx9_vm *)+sizeof(SyBlob)+sizeof(sxu32)));
	if( pSrc->iFlags & MEMOBJ_HASHMAP ){
		/* Increment reference count */
		((jx9_hashmap *)pSrc->x.pOther)->iRef++;
	}
	if( SyBlobLength(&pDest->sBlob) > 0 ){
		SyBlobRelease(&pDest->sBlob);
	}
	if( SyBlobLength(&pSrc->sBlob) > 0 ){
		SyBlobReadOnly(&pDest->sBlob, SyBlobData(&pSrc->sBlob), SyBlobLength(&pSrc->sBlob));
	}
	return SXRET_OK;
}
Example #7
0
/*
 * Convert a jx9_value so that it has types MEMOBJ_REAL or MEMOBJ_INT
 * or both.
 * Invalidate any prior representations. Every effort is made to force
 * the conversion, even if the input is a string that does not look 
 * completely like a number.Convert as much of the string as we can
 * and ignore the rest.
 */
JX9_PRIVATE sxi32 jx9MemObjToNumeric(jx9_value *pObj)
{
	if( pObj->iFlags & (MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL) ){
		if( pObj->iFlags & (MEMOBJ_BOOL|MEMOBJ_NULL) ){
			if( pObj->iFlags & MEMOBJ_NULL ){
				pObj->x.iVal = 0;
			}
			MemObjSetType(pObj, MEMOBJ_INT);
		}
		/* Already numeric */
		return  SXRET_OK;
	}
	if( pObj->iFlags & MEMOBJ_STRING ){
		sxi32 rc = SXERR_INVALID;
		sxu8 bReal = FALSE;
		SyString sString;
		SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
		/* Check if the given string looks like a numeric number */
		if( sString.nByte > 0 ){
			rc = SyStrIsNumeric(sString.zString, sString.nByte, &bReal, 0);
		}
		if( bReal ){
			jx9MemObjToReal(&(*pObj));
		}else{
			if( rc != SXRET_OK ){
				/* The input does not look at all like a number, set the value to 0 */
				pObj->x.iVal = 0;
			}else{
				/* Convert as much as we can */
				pObj->x.iVal = MemObjStringToInt(&(*pObj));
			}
			MemObjSetType(pObj, MEMOBJ_INT);
			SyBlobRelease(&pObj->sBlob);
		}
	}else if(pObj->iFlags & (MEMOBJ_HASHMAP|MEMOBJ_RES)){
		jx9MemObjToInteger(pObj);
	}else{
		/* Perform a blind cast */
		jx9MemObjToReal(&(*pObj));
	}
	return SXRET_OK;
}
Example #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;
}
Example #9
0
/*
 * Perform an addition operation of two jx9_values.
 * The reason this function is implemented here rather than 'vm.c'
 * is that the '+' operator is overloaded.
 * That is, the '+' operator is used for arithmetic operation and also 
 * used for operation on arrays [i.e: union]. When used with an array 
 * The + operator returns the right-hand array appended to the left-hand array.
 * For keys that exist in both arrays, the elements from the left-hand array
 * will be used, and the matching elements from the right-hand array will
 * be ignored.
 * This function take care of handling all the scenarios.
 */
JX9_PRIVATE sxi32 jx9MemObjAdd(jx9_value *pObj1, jx9_value *pObj2, int bAddStore)
{
	if( ((pObj1->iFlags|pObj2->iFlags) & MEMOBJ_HASHMAP) == 0 ){
			/* Arithemtic operation */
			jx9MemObjToNumeric(pObj1);
			jx9MemObjToNumeric(pObj2);
			if( (pObj1->iFlags|pObj2->iFlags) & MEMOBJ_REAL ){
				/* Floating point arithmetic */
				jx9_real a, b;
				if( (pObj1->iFlags & MEMOBJ_REAL) == 0 ){
					jx9MemObjToReal(pObj1);
				}
				if( (pObj2->iFlags & MEMOBJ_REAL) == 0 ){
					jx9MemObjToReal(pObj2);
				}
				a = pObj1->x.rVal;
				b = pObj2->x.rVal;
				pObj1->x.rVal = a+b;
				MemObjSetType(pObj1, MEMOBJ_REAL);
				/* Try to get an integer representation also */
				MemObjTryIntger(&(*pObj1));
			}else{
				/* Integer arithmetic */
				sxi64 a, b;
				a = pObj1->x.iVal;
				b = pObj2->x.iVal;
				pObj1->x.iVal = a+b;
				MemObjSetType(pObj1, MEMOBJ_INT);
			}
	}else{
		if( (pObj1->iFlags|pObj2->iFlags) & MEMOBJ_HASHMAP ){
			jx9_hashmap *pMap;
			sxi32 rc;
			if( bAddStore ){
				/* Do not duplicate the hashmap, use the left one since its an add&store operation.
				 */
				if( (pObj1->iFlags & MEMOBJ_HASHMAP) == 0 ){				
					/* Force a hashmap cast */
					rc = jx9MemObjToHashmap(pObj1);
					if( rc != SXRET_OK ){
						jx9VmThrowError(pObj1->pVm, 0, JX9_CTX_ERR, "JX9 is running out of memory while creating array");
						return rc;
					}
				}
				/* Point to the structure that describe the hashmap */
				pMap = (jx9_hashmap *)pObj1->x.pOther;
			}else{
				/* Create a new hashmap */
				pMap = jx9NewHashmap(pObj1->pVm, 0, 0);
				if( pMap == 0){
					jx9VmThrowError(pObj1->pVm, 0, JX9_CTX_ERR, "JX9 is running out of memory while creating array");
					return SXERR_MEM;
				}
			}
			if( !bAddStore ){
				if(pObj1->iFlags & MEMOBJ_HASHMAP ){
					/* Perform a hashmap duplication */
					jx9HashmapDup((jx9_hashmap *)pObj1->x.pOther, pMap);
				}else{
					if((pObj1->iFlags & MEMOBJ_NULL) == 0 ){
						/* Simple insertion */
						jx9HashmapInsert(pMap, 0, pObj1);
					}
				}
			}
			/* Perform the union */
			if(pObj2->iFlags & MEMOBJ_HASHMAP ){
				jx9HashmapUnion(pMap, (jx9_hashmap *)pObj2->x.pOther);
			}else{
				if((pObj2->iFlags & MEMOBJ_NULL) == 0 ){
					/* Simple insertion */
					jx9HashmapInsert(pMap, 0, pObj2);
				}
			}
			/* Reflect the change */
			if( pObj1->iFlags & MEMOBJ_STRING ){
				SyBlobRelease(&pObj1->sBlob);
			}
			pObj1->x.pOther = pMap;
			MemObjSetType(pObj1, MEMOBJ_HASHMAP);
		}
	}
	return SXRET_OK;
}